diff options
author | Gar <gar+gh@danger.computer> | 2021-02-25 02:54:50 +0300 |
---|---|---|
committer | Ruy Adorno <ruyadorno@hotmail.com> | 2021-03-05 00:05:08 +0300 |
commit | 4a5dd3a5a200b3f4f7b47168497d8e03dca3a2ca (patch) | |
tree | d34a1ea229b719c3cfbdce85899ceaf67b43e7ab /test | |
parent | b33c760cea7fe2696d35b5530abc1b455980fef1 (diff) |
fix(npm) pass npm context everywhere
Instead of files randomly requiring the npm singleton,
we pass it where it needs to go so that tests don't need
to do so much require mocking everywhere
PR-URL: https://github.com/npm/cli/pull/2772
Credit: @wraithgar
Close: #2772
Reviewed-by: @ruyadorno
Diffstat (limited to 'test')
82 files changed, 2814 insertions, 2466 deletions
diff --git a/test/lib/access.js b/test/lib/access.js index fb799f2df..3a732ad0a 100644 --- a/test/lib/access.js +++ b/test/lib/access.js @@ -1,17 +1,12 @@ const { test } = require('tap') const requireInject = require('require-inject') -const access = requireInject('../../lib/access.js', { - '../../lib/npm.js': { - flatOptions: {}, - }, -}) +const Access = require('../../lib/access.js') test('completion', t => { - const { completion } = access - + const access = new Access({ flatOptions: {} }) const testComp = (argv, expect) => { - const res = completion({conf: {argv: {remain: argv}}}) + const res = access.completion({conf: {argv: {remain: argv}}}) t.resolves(res, expect, argv.join(' ')) } @@ -32,7 +27,7 @@ test('completion', t => { testComp(['npm', 'access', 'revoke'], []) t.rejects( - completion({conf: {argv: {remain: ['npm', 'access', 'foobar']}}}), + access.completion({conf: {argv: {remain: ['npm', 'access', 'foobar']}}}), { message: 'foobar not recognized' } ) @@ -40,14 +35,16 @@ test('completion', t => { }) test('subcommand required', t => { - access([], (err) => { + const access = new Access({ flatOptions: {} }) + access.exec([], (err) => { t.equal(err, '\nUsage: Subcommand is required.\n\n' + access.usage) t.end() }) }) test('unrecognized subcommand', (t) => { - access(['blerg'], (err) => { + const access = new Access({ flatOptions: {} }) + access.exec(['blerg'], (err) => { t.match( err, /Usage: blerg is not a recognized subcommand/, @@ -58,7 +55,8 @@ test('unrecognized subcommand', (t) => { }) test('edit', (t) => { - access([ + const access = new Access({ flatOptions: {} }) + access.exec([ 'edit', '@scoped/another', ], (err) => { @@ -77,10 +75,8 @@ test('access public on unscoped package', (t) => { name: 'npm-access-public-pkg', }), }) - const access = requireInject('../../lib/access.js', { - '../../lib/npm.js': { prefix }, - }) - access([ + const access = new Access({ prefix }) + access.exec([ 'public', ], (err) => { t.match( @@ -98,7 +94,7 @@ test('access public on scoped package', (t) => { const prefix = t.testdir({ 'package.json': JSON.stringify({ name }), }) - const access = requireInject('../../lib/access.js', { + const Access = requireInject('../../lib/access.js', { libnpmaccess: { public: (pkg, { registry }) => { t.equal(pkg, name, 'should use pkg name ref') @@ -110,14 +106,12 @@ test('access public on scoped package', (t) => { return true }, }, - '../../lib/npm.js': { - flatOptions: { - registry: 'https://registry.npmjs.org', - }, - prefix, - }, }) - access([ + const access = new Access({ + flatOptions: { registry: 'https://registry.npmjs.org' }, + prefix, + }) + access.exec([ 'public', ], (err) => { t.ifError(err, 'npm access') @@ -129,10 +123,8 @@ test('access public on missing package.json', (t) => { const prefix = t.testdir({ node_modules: {}, }) - const access = requireInject('../../lib/access.js', { - '../../lib/npm.js': { prefix }, - }) - access([ + const access = new Access({ prefix }) + access.exec([ 'public', ], (err) => { t.match( @@ -149,10 +141,8 @@ test('access public on invalid package.json', (t) => { 'package.json': '{\n', node_modules: {}, }) - const access = requireInject('../../lib/access.js', { - '../../lib/npm.js': { prefix }, - }) - access([ + const access = new Access({ prefix }) + access.exec([ 'public', ], (err) => { t.match( @@ -170,10 +160,8 @@ test('access restricted on unscoped package', (t) => { name: 'npm-access-restricted-pkg', }), }) - const access = requireInject('../../lib/access.js', { - '../../lib/npm.js': { prefix }, - }) - access([ + const access = new Access({ prefix }) + access.exec([ 'restricted', ], (err) => { t.match( @@ -191,7 +179,7 @@ test('access restricted on scoped package', (t) => { const prefix = t.testdir({ 'package.json': JSON.stringify({ name }), }) - const access = requireInject('../../lib/access.js', { + const Access = requireInject('../../lib/access.js', { libnpmaccess: { restricted: (pkg, { registry }) => { t.equal(pkg, name, 'should use pkg name ref') @@ -203,14 +191,12 @@ test('access restricted on scoped package', (t) => { return true }, }, - '../../lib/npm.js': { - flatOptions: { - registry: 'https://registry.npmjs.org', - }, - prefix, - }, }) - access([ + const access = new Access({ + flatOptions: { registry: 'https://registry.npmjs.org' }, + prefix, + }) + access.exec([ 'restricted', ], (err) => { t.ifError(err, 'npm access') @@ -222,10 +208,8 @@ test('access restricted on missing package.json', (t) => { const prefix = t.testdir({ node_modules: {}, }) - const access = requireInject('../../lib/access.js', { - '../../lib/npm.js': { prefix }, - }) - access([ + const access = new Access({ prefix }) + access.exec([ 'restricted', ], (err) => { t.match( @@ -242,10 +226,8 @@ test('access restricted on invalid package.json', (t) => { 'package.json': '{\n', node_modules: {}, }) - const access = requireInject('../../lib/access.js', { - '../../lib/npm.js': { prefix }, - }) - access([ + const access = new Access({ prefix }) + access.exec([ 'restricted', ], (err) => { t.match( @@ -259,7 +241,7 @@ test('access restricted on invalid package.json', (t) => { test('access grant read-only', (t) => { t.plan(5) - const access = requireInject('../../lib/access.js', { + const Access = requireInject('../../lib/access.js', { libnpmaccess: { grant: (spec, team, permissions) => { t.equal(spec, '@scoped/another', 'should use expected spec') @@ -268,9 +250,9 @@ test('access grant read-only', (t) => { return true }, }, - '../../lib/npm.js': {}, }) - access([ + const access = new Access({}) + access.exec([ 'grant', 'read-only', 'myorg:myteam', @@ -283,7 +265,7 @@ test('access grant read-only', (t) => { test('access grant read-write', (t) => { t.plan(5) - const access = requireInject('../../lib/access.js', { + const Access = requireInject('../../lib/access.js', { libnpmaccess: { grant: (spec, team, permissions) => { t.equal(spec, '@scoped/another', 'should use expected spec') @@ -292,9 +274,9 @@ test('access grant read-write', (t) => { return true }, }, - '../../lib/npm.js': {}, }) - access([ + const access = new Access({}) + access.exec([ 'grant', 'read-write', 'myorg:myteam', @@ -312,7 +294,7 @@ test('access grant current cwd', (t) => { name: 'yargs', }), }) - const access = requireInject('../../lib/access.js', { + const Access = requireInject('../../lib/access.js', { libnpmaccess: { grant: (spec, team, permissions) => { t.equal(spec, 'yargs', 'should use expected spec') @@ -321,9 +303,9 @@ test('access grant current cwd', (t) => { return true }, }, - '../../lib/npm.js': { prefix }, }) - access([ + const access = new Access({ prefix }) + access.exec([ 'grant', 'read-write', 'myorg:myteam', @@ -334,7 +316,8 @@ test('access grant current cwd', (t) => { }) test('access grant others', (t) => { - access([ + const access = new Access({ flatOptions: {} }) + access.exec([ 'grant', 'rerere', 'myorg:myteam', @@ -350,7 +333,8 @@ test('access grant others', (t) => { }) test('access grant missing team args', (t) => { - access([ + const access = new Access({ flatOptions: {} }) + access.exec([ 'grant', 'read-only', undefined, @@ -366,7 +350,8 @@ test('access grant missing team args', (t) => { }) test('access grant malformed team arg', (t) => { - access([ + const access = new Access({ flatOptions: {} }) + access.exec([ 'grant', 'read-only', 'foo', @@ -383,7 +368,7 @@ test('access grant malformed team arg', (t) => { test('access 2fa-required/2fa-not-required', t => { t.plan(2) - const access = requireInject('../../lib/access.js', { + const Access = requireInject('../../lib/access.js', { libnpmaccess: { tfaRequired: (spec) => { t.equal(spec, '@scope/pkg', 'should use expected spec') @@ -394,15 +379,15 @@ test('access 2fa-required/2fa-not-required', t => { return true }, }, - '../../lib/npm.js': {}, }) + const access = new Access({}) - access(['2fa-required', '@scope/pkg'], er => { + access.exec(['2fa-required', '@scope/pkg'], er => { if (er) throw er }) - access(['2fa-not-required', 'unscoped-pkg'], er => { + access.exec(['2fa-not-required', 'unscoped-pkg'], er => { if (er) throw er }) @@ -410,7 +395,7 @@ test('access 2fa-required/2fa-not-required', t => { test('access revoke', (t) => { t.plan(4) - const access = requireInject('../../lib/access.js', { + const Access = requireInject('../../lib/access.js', { libnpmaccess: { revoke: (spec, team) => { t.equal(spec, '@scoped/another', 'should use expected spec') @@ -418,9 +403,9 @@ test('access revoke', (t) => { return true }, }, - '../../lib/npm.js': {}, }) - access([ + const access = new Access({}) + access.exec([ 'revoke', 'myorg:myteam', '@scoped/another', @@ -431,7 +416,8 @@ test('access revoke', (t) => { }) test('access revoke missing team args', (t) => { - access([ + const access = new Access({ flatOptions: {} }) + access.exec([ 'revoke', undefined, '@scoped/another', @@ -446,7 +432,8 @@ test('access revoke missing team args', (t) => { }) test('access revoke malformed team arg', (t) => { - access([ + const access = new Access({ flatOptions: {} }) + access.exec([ 'revoke', 'foo', '@scoped/another', @@ -462,7 +449,7 @@ test('access revoke malformed team arg', (t) => { test('npm access ls-packages with no team', (t) => { t.plan(3) - const access = requireInject('../../lib/access.js', { + const Access = requireInject('../../lib/access.js', { libnpmaccess: { lsPackages: (entity) => { t.equal(entity, 'foo', 'should use expected entity') @@ -471,9 +458,9 @@ test('npm access ls-packages with no team', (t) => { }, '../../lib/utils/get-identity.js': () => Promise.resolve('foo'), '../../lib/utils/output.js': () => null, - '../../lib/npm.js': {}, }) - access([ + const access = new Access({}) + access.exec([ 'ls-packages', ], (err) => { t.ifError(err, 'npm access') @@ -483,7 +470,7 @@ test('npm access ls-packages with no team', (t) => { test('access ls-packages on team', (t) => { t.plan(3) - const access = requireInject('../../lib/access.js', { + const Access = requireInject('../../lib/access.js', { libnpmaccess: { lsPackages: (entity) => { t.equal(entity, 'myorg:myteam', 'should use expected entity') @@ -491,9 +478,9 @@ test('access ls-packages on team', (t) => { }, }, '../../lib/utils/output.js': () => null, - '../../lib/npm.js': {}, }) - access([ + const access = new Access({}) + access.exec([ 'ls-packages', 'myorg:myteam', ], (err) => { @@ -509,7 +496,7 @@ test('access ls-collaborators on current', (t) => { name: 'yargs', }), }) - const access = requireInject('../../lib/access.js', { + const Access = requireInject('../../lib/access.js', { libnpmaccess: { lsCollaborators: (spec) => { t.equal(spec, 'yargs', 'should use expected spec') @@ -517,9 +504,9 @@ test('access ls-collaborators on current', (t) => { }, }, '../../lib/utils/output.js': () => null, - '../../lib/npm.js': { prefix }, }) - access([ + const access = new Access({ prefix }) + access.exec([ 'ls-collaborators', ], (err) => { t.ifError(err, 'npm access') @@ -529,7 +516,7 @@ test('access ls-collaborators on current', (t) => { test('access ls-collaborators on spec', (t) => { t.plan(3) - const access = requireInject('../../lib/access.js', { + const Access = requireInject('../../lib/access.js', { libnpmaccess: { lsCollaborators: (spec) => { t.equal(spec, 'yargs', 'should use expected spec') @@ -537,9 +524,9 @@ test('access ls-collaborators on spec', (t) => { }, }, '../../lib/utils/output.js': () => null, - '../../lib/npm.js': {}, }) - access([ + const access = new Access({}) + access.exec([ 'ls-collaborators', 'yargs', ], (err) => { diff --git a/test/lib/adduser.js b/test/lib/adduser.js index 36f59e085..32fd97c1b 100644 --- a/test/lib/adduser.js +++ b/test/lib/adduser.js @@ -16,7 +16,7 @@ let failSave = false let deletedConfig = {} let registryOutput = '' let setConfig = {} -const authDummy = (options) => { +const authDummy = (npm, options) => { if (!options.fromFlatOptions) throw new Error('did not pass full flatOptions to auth function') @@ -37,46 +37,49 @@ const deleteMock = (key, where) => { [key]: where, } } -const adduser = requireInject('../../lib/adduser.js', { +const npm = { + flatOptions: _flatOptions, + config: { + delete: deleteMock, + get (key, where) { + if (!where || where === 'user') + return _flatOptions[key] + }, + getCredentialsByURI, + async save () { + if (failSave) + throw new Error('error saving user config') + }, + set (key, value, where) { + setConfig = { + ...setConfig, + [key]: { + value, + where, + }, + } + }, + setCredentialsByURI, + }, +} + +const AddUser = requireInject('../../lib/adduser.js', { npmlog: { disableProgress: () => null, notice: (_, msg) => { registryOutput = msg }, }, - '../../lib/npm.js': { - flatOptions: _flatOptions, - config: { - delete: deleteMock, - get (key, where) { - if (!where || where === 'user') - return _flatOptions[key] - }, - getCredentialsByURI, - async save () { - if (failSave) - throw new Error('error saving user config') - }, - set (key, value, where) { - setConfig = { - ...setConfig, - [key]: { - value, - where, - }, - } - }, - setCredentialsByURI, - }, - }, '../../lib/utils/output.js': msg => { result = msg }, '../../lib/auth/legacy.js': authDummy, }) +const adduser = new AddUser(npm) + test('simple login', (t) => { - adduser([], (err) => { + adduser.exec([], (err) => { t.ifError(err, 'npm adduser') t.equal( @@ -129,7 +132,7 @@ test('simple login', (t) => { test('bad auth type', (t) => { _flatOptions.authType = 'foo' - adduser([], (err) => { + adduser.exec([], (err) => { t.match( err, /Error: no such auth module/, @@ -147,7 +150,7 @@ test('bad auth type', (t) => { test('scoped login', (t) => { _flatOptions.scope = '@myscope' - adduser([], (err) => { + adduser.exec([], (err) => { t.ifError(err, 'npm adduser') t.deepEqual( @@ -168,7 +171,7 @@ test('scoped login with valid scoped registry config', (t) => { _flatOptions['@myscope:registry'] = 'https://diff-registry.npmjs.com/' _flatOptions.scope = '@myscope' - adduser([], (err) => { + adduser.exec([], (err) => { t.ifError(err, 'npm adduser') t.deepEqual( @@ -189,7 +192,7 @@ test('scoped login with valid scoped registry config', (t) => { test('save config failure', (t) => { failSave = true - adduser([], (err) => { + adduser.exec([], (err) => { t.match( err, /error saving user config/, diff --git a/test/lib/audit.js b/test/lib/audit.js index 3d6296bac..6fd9c8a2c 100644 --- a/test/lib/audit.js +++ b/test/lib/audit.js @@ -1,6 +1,5 @@ const t = require('tap') const requireInject = require('require-inject') -const audit = require('../../lib/audit.js') t.test('should audit using Arborist', t => { let ARB_ARGS = null @@ -10,13 +9,13 @@ t.test('should audit using Arborist', t => { let OUTPUT_CALLED = false let ARB_OBJ = null - const audit = requireInject('../../lib/audit.js', { - '../../lib/npm.js': { - prefix: 'foo', - flatOptions: { - json: false, - }, + const npm = { + prefix: 'foo', + flatOptions: { + json: false, }, + } + const Audit = requireInject('../../lib/audit.js', { 'npm-audit-report': () => { AUDIT_REPORT_CALLED = true return { @@ -32,7 +31,7 @@ t.test('should audit using Arborist', t => { this.auditReport = {} } }, - '../../lib/utils/reify-finish.js': arb => { + '../../lib/utils/reify-finish.js': (npm, arb) => { if (arb !== ARB_OBJ) throw new Error('got wrong object passed to reify-output') @@ -43,8 +42,10 @@ t.test('should audit using Arborist', t => { }, }) + const audit = new Audit(npm) + t.test('audit', t => { - audit([], () => { + audit.exec([], () => { t.match(ARB_ARGS, { audit: true, path: 'foo' }) t.equal(AUDIT_CALLED, true, 'called audit') t.equal(AUDIT_REPORT_CALLED, true, 'called audit report') @@ -54,7 +55,7 @@ t.test('should audit using Arborist', t => { }) t.test('audit fix', t => { - audit(['fix'], () => { + audit.exec(['fix'], () => { t.equal(REIFY_FINISH_CALLED, true, 'called reify output') t.end() }) @@ -64,13 +65,14 @@ t.test('should audit using Arborist', t => { }) t.test('should audit - json', t => { - const audit = requireInject('../../lib/audit.js', { - '../../lib/npm.js': { - prefix: 'foo', - flatOptions: { - json: true, - }, + const npm = { + prefix: 'foo', + flatOptions: { + json: true, }, + } + + const Audit = requireInject('../../lib/audit.js', { 'npm-audit-report': () => ({ report: 'there are vulnerabilities', exitCode: 0, @@ -83,8 +85,9 @@ t.test('should audit - json', t => { '../../lib/utils/reify-output.js': () => {}, '../../lib/utils/output.js': () => {}, }) + const audit = new Audit(npm) - audit([], (err) => { + audit.exec([], (err) => { t.notOk(err, 'no errors') t.end() }) @@ -95,17 +98,17 @@ t.test('report endpoint error', t => { t.test(`json=${json}`, t => { const OUTPUT = [] const LOGS = [] - const mocks = { - '../../lib/npm.js': { - prefix: 'foo', - command: 'audit', - flatOptions: { - json, - }, - log: { - warn: (...warning) => LOGS.push(warning), - }, + const npm = { + prefix: 'foo', + command: 'audit', + flatOptions: { + json, }, + log: { + warn: (...warning) => LOGS.push(warning), + }, + } + const Audit = requireInject('../../lib/audit.js', { 'npm-audit-report': () => { throw new Error('should not call audit report when there are errors') }, @@ -130,15 +133,10 @@ t.test('report endpoint error', t => { '../../lib/utils/output.js': (...msg) => { OUTPUT.push(msg) }, - } - // have to pass mocks to both to get the npm and output set right - const auditError = requireInject('../../lib/utils/audit-error.js', mocks) - const audit = requireInject('../../lib/audit.js', { - ...mocks, - '../../lib/utils/audit-error.js': auditError, }) + const audit = new Audit(npm) - audit([], (err) => { + audit.exec([], (err) => { t.equal(err, 'audit endpoint returned an error') t.strictSame(OUTPUT, [ [ @@ -168,6 +166,8 @@ t.test('report endpoint error', t => { }) t.test('completion', t => { + const Audit = require('../../lib/audit.js') + const audit = new Audit({}) t.test('fix', async t => { t.resolveMatch(audit.completion({ conf: { argv: { remain: ['npm', 'audit'] } } }), ['fix'], 'completes to fix') t.end() diff --git a/test/lib/auth/legacy.js b/test/lib/auth/legacy.js index f926ae130..f5297c581 100644 --- a/test/lib/auth/legacy.js +++ b/test/lib/auth/legacy.js @@ -13,19 +13,19 @@ const legacy = requireInject('../../../lib/auth/legacy.js', { }, }, 'npm-profile': profile, - '../../../lib/utils/open-url.js': (url, msg, cb) => { - if (url) - cb() - else { - cb(Object.assign( - new Error('failed open url'), - { code: 'ERROR' } - )) - } + '../../../lib/utils/open-url.js': (npm, url, msg) => { + if (!url) + throw Object.assign(new Error('failed open url'), { code: 'ERROR' }) }, '../../../lib/utils/read-user-info.js': read, }) +const npm = { + config: { + get: () => null, + }, +} + test('login using username/password with token result', async (t) => { profile.login = () => { return { token } @@ -34,7 +34,7 @@ test('login using username/password with token result', async (t) => { const { message, newCreds, - } = await legacy({ + } = await legacy(npm, { creds: { username: 'u', password: 'p', @@ -75,7 +75,7 @@ test('login using username/password with user info result', async (t) => { const { message, newCreds, - } = await legacy({ + } = await legacy(npm, { creds: { username: 'u', password: 'p', @@ -126,7 +126,7 @@ test('login otp requested', async (t) => { const { message, newCreds, - } = await legacy({ + } = await legacy(npm, { creds: { username: 'u', password: 'p', @@ -162,7 +162,7 @@ test('login missing basic credential info', async (t) => { )) await t.rejects( - legacy({ + legacy(npm, { creds: { username: 'u', password: 'p', @@ -196,7 +196,7 @@ test('create new user when user not found', async (t) => { const { message, newCreds, - } = await legacy({ + } = await legacy(npm, { creds: { username: 'u', password: 'p', @@ -246,7 +246,7 @@ test('prompts for user info if required', async (t) => { const { message, newCreds, - } = await legacy({ + } = await legacy(npm, { creds: { alwaysAuth: true, }, @@ -304,7 +304,7 @@ test('request otp when creating new user', async (t) => { } read.otp = () => Promise.resolve('1234') - await legacy({ + await legacy(npm, { creds: { username: 'u', password: 'p', @@ -333,7 +333,7 @@ test('unknown error during user creation', async (t) => { )) await t.rejects( - legacy({ + legacy(npm, { creds: { username: 'u', password: 'p', @@ -358,7 +358,7 @@ test('open url error', async (t) => { } await t.rejects( - legacy({ + legacy(npm, { creds: { username: 'u', password: 'p', @@ -377,7 +377,7 @@ test('open url error', async (t) => { test('login no credentials provided', async (t) => { profile.login = () => ({ token }) - await legacy({ + await legacy(npm, { creds: { username: undefined, password: undefined, @@ -401,7 +401,7 @@ test('login no credentials provided', async (t) => { test('scoped login', async (t) => { profile.login = () => ({ token }) - const { message } = await legacy({ + const { message } = await legacy(npm, { creds: { username: 'u', password: 'p', diff --git a/test/lib/auth/oauth.js b/test/lib/auth/oauth.js index 82d478b52..c2f4c3443 100644 --- a/test/lib/auth/oauth.js +++ b/test/lib/auth/oauth.js @@ -9,21 +9,21 @@ test('oauth login', (t) => { scope: 'myscope', } + const npm = { + config: { + set: (key, value) => { + t.equal(key, 'sso-type', 'should define sso-type') + t.equal(value, 'oauth', 'should set sso-type to oauth') + }, + }, + } const oauth = requireInject('../../../lib/auth/oauth.js', { - '../../../lib/auth/sso.js': (opts) => { + '../../../lib/auth/sso.js': (npm, opts) => { t.equal(opts, oauthOpts, 'should forward opts') }, - '../../../lib/npm.js': { - config: { - set: (key, value) => { - t.equal(key, 'sso-type', 'should define sso-type') - t.equal(value, 'oauth', 'should set sso-type to oauth') - }, - }, - }, }) - oauth(oauthOpts) + oauth(npm, oauthOpts) t.end() }) diff --git a/test/lib/auth/saml.js b/test/lib/auth/saml.js index 87fa6688b..b8c21f649 100644 --- a/test/lib/auth/saml.js +++ b/test/lib/auth/saml.js @@ -9,21 +9,21 @@ test('saml login', (t) => { scope: 'myscope', } + const npm = { + config: { + set: (key, value) => { + t.equal(key, 'sso-type', 'should define sso-type') + t.equal(value, 'saml', 'should set sso-type to saml') + }, + }, + } const saml = requireInject('../../../lib/auth/saml.js', { - '../../../lib/auth/sso.js': (opts) => { + '../../../lib/auth/sso.js': (npm, opts) => { t.equal(opts, samlOpts, 'should forward opts') }, - '../../../lib/npm.js': { - config: { - set: (key, value) => { - t.equal(key, 'sso-type', 'should define sso-type') - t.equal(value, 'saml', 'should set sso-type to saml') - }, - }, - }, }) - saml(samlOpts) + saml(npm, samlOpts) t.end() }) diff --git a/test/lib/auth/sso.js b/test/lib/auth/sso.js index 1fc04c64c..9d77e7c27 100644 --- a/test/lib/auth/sso.js +++ b/test/lib/auth/sso.js @@ -22,10 +22,7 @@ const sso = requireInject('../../../lib/auth/sso.js', { }, 'npm-profile': profile, 'npm-registry-fetch': npmFetch, - '../../../lib/npm.js': { - flatOptions: _flatOptions, - }, - '../../../lib/utils/open-url.js': (url, msg, cb) => { + '../../../lib/utils/open-url.js': (npm, url, msg, cb) => { if (url) cb() else { @@ -47,11 +44,15 @@ const sso = requireInject('../../../lib/auth/sso.js', { }, }) +const npm = { + flatOptions: _flatOptions, +} + test('empty login', async (t) => { _flatOptions.ssoType = false await t.rejects( - sso({}), + sso(npm, {}), { message: 'Missing option: sso-type' }, 'should throw if no sso-type defined in flatOptions' ) @@ -92,7 +93,7 @@ test('simple login', async (t) => { const { message, newCreds, - } = await sso({ + } = await sso(npm, { creds: {}, registry: 'https://registry.npmjs.org/', scope: '', @@ -157,7 +158,7 @@ test('polling retry', async (t) => { )) } - await sso({ + await sso(npm, { creds: {}, registry: 'https://registry.npmjs.org/', scope: '', @@ -177,7 +178,7 @@ test('polling error', async (t) => { )) await t.rejects( - sso({ + sso(npm, { creds: {}, registry: 'https://registry.npmjs.org/', scope: '', @@ -196,7 +197,7 @@ test('no token retrieved from loginCouch', async (t) => { profile.loginCouch = () => ({}) await t.rejects( - sso({ + sso(npm, { creds: {}, registry: 'https://registry.npmjs.org/', scope: '', @@ -214,7 +215,7 @@ test('no sso url retrieved from loginCouch', async (t) => { profile.loginCouch = () => Promise.resolve({ token }) await t.rejects( - sso({ + sso(npm, { creds: {}, registry: 'https://registry.npmjs.org/', scope: '', @@ -235,7 +236,7 @@ test('scoped login', async (t) => { const { message, newCreds, - } = await sso({ + } = await sso(npm, { creds: {}, registry: 'https://diff-registry.npmjs.org/', scope: 'myscope', diff --git a/test/lib/bin.js b/test/lib/bin.js index c5ed2a91b..e96eb91af 100644 --- a/test/lib/bin.js +++ b/test/lib/bin.js @@ -5,14 +5,15 @@ test('bin', (t) => { t.plan(3) const dir = '/bin/dir' - const bin = requireInject('../../lib/bin.js', { - '../../lib/npm.js': { bin: dir, flatOptions: { global: false } }, + const Bin = requireInject('../../lib/bin.js', { '../../lib/utils/output.js': (output) => { t.equal(output, dir, 'prints the correct directory') }, }) - bin([], (err) => { + const bin = new Bin({ bin: dir, flatOptions: { global: false } }) + + bin.exec([], (err) => { t.ifError(err, 'npm bin') t.ok('should have printed directory') }) @@ -30,15 +31,16 @@ test('bin -g', (t) => { } const dir = '/bin/dir' - const bin = requireInject('../../lib/bin.js', { - '../../lib/npm.js': { bin: dir, flatOptions: { global: true } }, + const Bin = requireInject('../../lib/bin.js', { '../../lib/utils/path.js': [dir], '../../lib/utils/output.js': (output) => { t.equal(output, dir, 'prints the correct directory') }, }) - bin([], (err) => { + const bin = new Bin({ bin: dir, flatOptions: { global: true } }) + + bin.exec([], (err) => { t.ifError(err, 'npm bin') t.ok('should have printed directory') }) @@ -56,15 +58,15 @@ test('bin -g (not in path)', (t) => { } const dir = '/bin/dir' - const bin = requireInject('../../lib/bin.js', { - '../../lib/npm.js': { bin: dir, flatOptions: { global: true } }, + const Bin = requireInject('../../lib/bin.js', { '../../lib/utils/path.js': ['/not/my/dir'], '../../lib/utils/output.js': (output) => { t.equal(output, dir, 'prints the correct directory') }, }) + const bin = new Bin({ bin: dir, flatOptions: { global: true } }) - bin([], (err) => { + bin.exec([], (err) => { t.ifError(err, 'npm bin') t.ok('should have printed directory') }) diff --git a/test/lib/birthday.js b/test/lib/birthday.js index 3b8110fc8..c818223fb 100644 --- a/test/lib/birthday.js +++ b/test/lib/birthday.js @@ -1,5 +1,4 @@ const t = require('tap') -const requireInject = require('require-inject') const npm = { flatOptions: { yes: false, @@ -17,10 +16,9 @@ const npm = { }, } -const birthday = requireInject('../../lib/birthday.js', { - '../../lib/npm.js': npm, -}) +const Birthday = require('../../lib/birthday.js') +const birthday = new Birthday(npm) let calledCb = false -birthday([], () => calledCb = true) +birthday.exec([], () => calledCb = true) t.equal(calledCb, true, 'called the callback') diff --git a/test/lib/bugs.js b/test/lib/bugs.js index 992bd9f61..e98131f11 100644 --- a/test/lib/bugs.js +++ b/test/lib/bugs.js @@ -43,17 +43,18 @@ const pacote = { // keep a tally of which urls got opened const opened = {} -const openUrl = (url, errMsg, cb) => { +const openUrl = async (npm, url, errMsg) => { opened[url] = opened[url] || 0 opened[url]++ - process.nextTick(cb) } -const bugs = requireInject('../../lib/bugs.js', { +const Bugs = requireInject('../../lib/bugs.js', { pacote, '../../lib/utils/open-url.js': openUrl, }) +const bugs = new Bugs({ flatOptions: {} }) + t.test('open bugs urls', t => { const expect = { nobugs: 'https://www.npmjs.com/package/nobugs', @@ -68,7 +69,7 @@ t.test('open bugs urls', t => { t.plan(keys.length) keys.forEach(pkg => { t.test(pkg, t => { - bugs([pkg], (er) => { + bugs.exec([pkg], (er) => { if (er) throw er t.equal(opened[expect[pkg]], 1, 'opened expected url', {opened}) @@ -79,7 +80,7 @@ t.test('open bugs urls', t => { }) t.test('open default package if none specified', t => { - bugs([], (er) => { + bugs.exec([], (er) => { if (er) throw er t.equal(opened['https://example.com'], 2, 'opened expected url', {opened}) diff --git a/test/lib/cache.js b/test/lib/cache.js index 05d269dd4..67499f37e 100644 --- a/test/lib/cache.js +++ b/test/lib/cache.js @@ -58,27 +58,26 @@ const cacache = { }, } -const mocks = { +const Cache = requireInject('../../lib/cache.js', { cacache, npmlog, pacote, rimraf, - '../../lib/npm.js': npm, '../../lib/utils/output.js': output, '../../lib/utils/usage.js': usageUtil, -} +}) -const cache = requireInject('../../lib/cache.js', mocks) +const cache = new Cache(npm) t.test('cache no args', t => { - cache([], err => { + cache.exec([], err => { t.equal(err.message, 'usage instructions', 'should throw usage instructions') t.end() }) }) t.test('cache clean', t => { - cache(['clean'], err => { + cache.exec(['clean'], err => { t.match(err.message, 'the npm cache self-heals', 'should throw warning') t.end() }) @@ -91,7 +90,7 @@ t.test('cache clean (force)', t => { flatOptions.force = false }) - cache(['clear'], err => { + cache.exec(['clear'], err => { t.ifError(err) t.equal(rimrafPath, path.join(npm.cache, '_cacache')) t.end() @@ -99,7 +98,7 @@ t.test('cache clean (force)', t => { }) t.test('cache clean with arg', t => { - cache(['rm', 'pkg'], err => { + cache.exec(['rm', 'pkg'], err => { t.match(err.message, 'does not accept arguments', 'should throw error') t.end() }) @@ -110,7 +109,7 @@ t.test('cache add no arg', t => { logOutput = [] }) - cache(['add'], err => { + cache.exec(['add'], err => { t.strictSame(logOutput, [ ['silly', 'cache add', 'args', []], ], 'logs correctly') @@ -126,7 +125,7 @@ t.test('cache add pkg only', t => { tarballStreamOpts = {} }) - cache(['add', 'mypkg'], err => { + cache.exec(['add', 'mypkg'], err => { t.ifError(err) t.strictSame(logOutput, [ ['silly', 'cache add', 'args', ['mypkg']], @@ -145,7 +144,7 @@ t.test('cache add pkg w/ spec modifier', t => { tarballStreamOpts = {} }) - cache(['add', 'mypkg', 'latest'], err => { + cache.exec(['add', 'mypkg', 'latest'], err => { t.ifError(err) t.strictSame(logOutput, [ ['silly', 'cache add', 'args', ['mypkg', 'latest']], @@ -162,7 +161,7 @@ t.test('cache verify', t => { outputOutput = [] }) - cache(['verify'], err => { + cache.exec(['verify'], err => { t.ifError(err) t.match(outputOutput, [ `Cache verified and compressed (${path.join(npm.cache, '_cacache')})`, @@ -189,7 +188,7 @@ t.test('cache verify w/ extra output', t => { delete cacacheVerifyStats.missingContent }) - cache(['check'], err => { + cache.exec(['check'], err => { t.ifError(err) t.match(outputOutput, [ `Cache verified and compressed (~${path.join('/fake/path', '_cacache')})`, diff --git a/test/lib/ci.js b/test/lib/ci.js index 28c66b056..3419218ef 100644 --- a/test/lib/ci.js +++ b/test/lib/ci.js @@ -9,19 +9,8 @@ const requireInject = require('require-inject') test('should ignore scripts with --ignore-scripts', (t) => { const SCRIPTS = [] let REIFY_CALLED = false - const ci = requireInject('../../lib/ci.js', { + const CI = requireInject('../../lib/ci.js', { '../../lib/utils/reify-finish.js': async () => {}, - '../../lib/npm.js': { - globalDir: 'path/to/node_modules/', - prefix: 'foo', - flatOptions: { - global: false, - ignoreScripts: true, - }, - config: { - get: () => false, - }, - }, '@npmcli/run-script': ({ event }) => { SCRIPTS.push(event) }, @@ -32,7 +21,20 @@ test('should ignore scripts with --ignore-scripts', (t) => { } }, }) - ci([], er => { + + const ci = new CI({ + globalDir: 'path/to/node_modules/', + prefix: 'foo', + flatOptions: { + global: false, + ignoreScripts: true, + }, + config: { + get: () => false, + }, + }) + + ci.exec([], er => { if (er) throw er t.equal(REIFY_CALLED, true, 'called reify') @@ -87,13 +89,7 @@ test('should use Arborist and run-script', (t) => { const expectRimrafs = 3 let actualRimrafs = 0 - const ci = requireInject('../../lib/ci.js', { - '../../lib/npm.js': { - prefix: path, - flatOptions: { - global: false, - }, - }, + const CI = requireInject('../../lib/ci.js', { '../../lib/utils/reify-finish.js': async () => {}, '@npmcli/run-script': opts => { t.match(opts, { event: scripts.shift() }) @@ -118,7 +114,15 @@ test('should use Arborist and run-script', (t) => { t.ok(arb, 'gets arborist tree') }, }) - ci(null, er => { + + const ci = new CI({ + prefix: path, + flatOptions: { + global: false, + }, + }) + + ci.exec(null, er => { if (er) throw er for (const [msg, result] of Object.entries(timers)) @@ -131,13 +135,7 @@ test('should use Arborist and run-script', (t) => { }) test('should pass flatOptions to Arborist.reify', (t) => { - const ci = requireInject('../../lib/ci.js', { - '../../lib/npm.js': { - prefix: 'foo', - flatOptions: { - production: true, - }, - }, + const CI = requireInject('../../lib/ci.js', { '../../lib/utils/reify-finish.js': async () => {}, '@npmcli/run-script': opts => {}, '@npmcli/arborist': function () { @@ -148,7 +146,13 @@ test('should pass flatOptions to Arborist.reify', (t) => { } }, }) - ci(null, er => { + const ci = new CI({ + prefix: 'foo', + flatOptions: { + production: true, + }, + }) + ci.exec(null, er => { if (er) throw er }) @@ -160,13 +164,7 @@ test('should throw if package-lock.json or npm-shrinkwrap missing', (t) => { 'package.json': 'some info', }) - const ci = requireInject('../../lib/ci.js', { - '../../lib/npm.js': { - prefix: testDir, - flatOptions: { - global: false, - }, - }, + const CI = requireInject('../../lib/ci.js', { '@npmcli/run-script': opts => {}, '../../lib/utils/reify-finish.js': async () => {}, npmlog: { @@ -175,7 +173,13 @@ test('should throw if package-lock.json or npm-shrinkwrap missing', (t) => { }, }, }) - ci(null, (err, res) => { + const ci = new CI({ + prefix: testDir, + flatOptions: { + global: false, + }, + }) + ci.exec(null, (err, res) => { t.ok(err, 'throws error when there is no package-lock') t.notOk(res) t.end() @@ -183,17 +187,17 @@ test('should throw if package-lock.json or npm-shrinkwrap missing', (t) => { }) test('should throw ECIGLOBAL', (t) => { - const ci = requireInject('../../lib/ci.js', { - '../../lib/npm.js': { - prefix: 'foo', - flatOptions: { - global: true, - }, - }, + const CI = requireInject('../../lib/ci.js', { '@npmcli/run-script': opts => {}, '../../lib/utils/reify-finish.js': async () => {}, }) - ci(null, (err, res) => { + const ci = new CI({ + prefix: 'foo', + flatOptions: { + global: true, + }, + }) + ci.exec(null, (err, res) => { t.equals(err.code, 'ECIGLOBAL', 'throws error with global packages') t.notOk(res) t.end() @@ -207,13 +211,7 @@ test('should remove existing node_modules before installing', (t) => { }, }) - const ci = requireInject('../../lib/ci.js', { - '../../lib/npm.js': { - prefix: testDir, - flatOptions: { - global: false, - }, - }, + const CI = requireInject('../../lib/ci.js', { '@npmcli/run-script': opts => {}, '../../lib/utils/reify-finish.js': async () => {}, '@npmcli/arborist': function () { @@ -229,7 +227,14 @@ test('should remove existing node_modules before installing', (t) => { }, }) - ci(null, er => { + const ci = new CI({ + prefix: testDir, + flatOptions: { + global: false, + }, + }) + + ci.exec(null, er => { if (er) throw er }) diff --git a/test/lib/completion.js b/test/lib/completion.js index 19f70df20..89e8134eb 100644 --- a/test/lib/completion.js +++ b/test/lib/completion.js @@ -75,8 +75,7 @@ const deref = (cmd) => { return cmd } -const completion = requireInject('../../lib/completion.js', { - '../../lib/npm.js': npm, +const Completion = requireInject('../../lib/completion.js', { '../../lib/utils/cmd-list.js': cmdList, '../../lib/utils/config.js': config, '../../lib/utils/deref-command.js': deref, @@ -85,6 +84,7 @@ const completion = requireInject('../../lib/completion.js', { output.push(line) }, }) +const completion = new Completion(npm) test('completion completion', async t => { const home = process.env.HOME @@ -125,11 +125,13 @@ test('completion completion wrong word count', async t => { }) test('completion errors in windows without bash', t => { - const compl = requireInject('../../lib/completion.js', { + const Compl = requireInject('../../lib/completion.js', { '../../lib/utils/is-windows-shell.js': true, }) - compl({}, (err) => { + const compl = new Compl() + + compl.exec({}, (err) => { t.match(err, { code: 'ENOTSUP', message: /completion supported only in MINGW/, @@ -162,7 +164,7 @@ test('dump script when completion is not being attempted', t => { }) } - completion({}, (err) => { + completion.exec({}, (err) => { if (err) throw err @@ -195,7 +197,7 @@ test('dump script exits correctly when EPIPE is emitted on stdout', t => { }) } - completion({}, (err) => { + completion.exec({}, (err) => { if (err) throw err @@ -228,7 +230,7 @@ test('non EPIPE errors cause failures', t => { }) } - completion({}, (err) => { + completion.exec({}, (err) => { t.equal(err.errno, 'ESOMETHINGELSE', 'propagated error') t.equal(data, completionScript, 'wrote the completion script') t.end() @@ -248,7 +250,7 @@ test('completion completes single command name', t => { output.length = 0 }) - completion(['npm', 'c'], (err, res) => { + completion.exec(['npm', 'c'], (err, res) => { if (err) throw err @@ -270,7 +272,7 @@ test('completion completes command names', t => { output.length = 0 }) - completion(['npm', 'a'], (err, res) => { + completion.exec(['npm', 'a'], (err, res) => { if (err) throw err @@ -292,7 +294,7 @@ test('completion of invalid command name does nothing', t => { output.length = 0 }) - completion(['npm', 'compute'], (err, res) => { + completion.exec(['npm', 'compute'], (err, res) => { if (err) throw err @@ -314,7 +316,7 @@ test('handles async completion function', t => { output.length = 0 }) - completion(['npm', 'promise', ''], (err, res) => { + completion.exec(['npm', 'promise', ''], (err, res) => { if (err) throw err @@ -343,7 +345,7 @@ test('completion triggers command completions', t => { output.length = 0 }) - completion(['npm', 'access', ''], (err, res) => { + completion.exec(['npm', 'access', ''], (err, res) => { if (err) throw err @@ -372,7 +374,7 @@ test('completion triggers filtered command completions', t => { output.length = 0 }) - completion(['npm', 'access', 'p'], (err, res) => { + completion.exec(['npm', 'access', 'p'], (err, res) => { if (err) throw err @@ -401,7 +403,7 @@ test('completions for commands that return nested arrays are joined', t => { output.length = 0 }) - completion(['npm', 'completion', ''], (err, res) => { + completion.exec(['npm', 'completion', ''], (err, res) => { if (err) throw err @@ -430,7 +432,7 @@ test('completions for commands that return nothing work correctly', t => { output.length = 0 }) - completion(['npm', 'donothing', ''], (err, res) => { + completion.exec(['npm', 'donothing', ''], (err, res) => { if (err) throw err @@ -459,7 +461,7 @@ test('completions for commands that return a single item work correctly', t => { output.length = 0 }) - completion(['npm', 'driveaboat', ''], (err, res) => { + completion.exec(['npm', 'driveaboat', ''], (err, res) => { if (err) throw err @@ -489,7 +491,7 @@ test('command completion for commands with no completion return no results', t = }) // quotes around adduser are to ensure coverage when unescaping commands - completion(['npm', '\'adduser\'', ''], (err, res) => { + completion.exec(['npm', '\'adduser\'', ''], (err, res) => { if (err) throw err @@ -520,7 +522,7 @@ test('command completion errors propagate', t => { accessCompletionError = false }) - completion(['npm', 'access', ''], (err, res) => { + completion.exec(['npm', 'access', ''], (err, res) => { t.match(err, /access completion failed/, 'catches the appropriate error') t.strictSame(npmConfig, { argv: { @@ -547,7 +549,7 @@ test('completion can complete flags', t => { output.length = 0 }) - completion(['npm', 'install', '--'], (err, res) => { + completion.exec(['npm', 'install', '--'], (err, res) => { if (err) throw err @@ -570,7 +572,7 @@ test('double dashes escape from flag completion', t => { output.length = 0 }) - completion(['npm', '--', 'install', '--'], (err, res) => { + completion.exec(['npm', '--', 'install', '--'], (err, res) => { if (err) throw err @@ -593,7 +595,7 @@ test('completion cannot complete options that take a value in mid-command', t => output.length = 0 }) - completion(['npm', '--registry', 'install'], (err, res) => { + completion.exec(['npm', '--registry', 'install'], (err, res) => { if (err) throw err diff --git a/test/lib/config.js b/test/lib/config.js index edaa6486c..c2420aefb 100644 --- a/test/lib/config.js +++ b/test/lib/config.js @@ -68,17 +68,17 @@ const usageUtil = () => 'usage instructions' const mocks = { '../../lib/utils/config.js': { defaults, types }, - '../../lib/npm.js': npm, '../../lib/utils/output.js': msg => { result = msg }, '../../lib/utils/usage.js': usageUtil, } -const config = requireInject('../../lib/config.js', mocks) +const Config = requireInject('../../lib/config.js', mocks) +const config = new Config(npm) t.test('config no args', t => { - config([], (err) => { + config.exec([], (err) => { t.match(err, /usage instructions/, 'should not error out on empty locations') t.end() }) @@ -94,7 +94,7 @@ t.test('config list', t => { delete npm.config.find }) - config(['list'], (err) => { + config.exec(['list'], (err) => { t.ifError(err, 'npm config list') t.matchSnapshot(result, 'should list configs') }) @@ -120,7 +120,7 @@ t.test('config list overrides', t => { delete npm.config.find }) - config(['list'], (err) => { + config.exec(['list'], (err) => { t.ifError(err, 'npm config list') t.matchSnapshot(result, 'should list overridden configs') }) @@ -138,7 +138,7 @@ t.test('config list --long', t => { result = '' }) - config(['list'], (err) => { + config.exec(['list'], (err) => { t.ifError(err, 'npm config list --long') t.matchSnapshot(result, 'should list all configs') }) @@ -163,7 +163,7 @@ t.test('config list --json', t => { result = '' }) - config(['list'], (err) => { + config.exec(['list'], (err) => { t.ifError(err, 'npm config list --json') t.deepEqual( JSON.parse(result), @@ -179,7 +179,7 @@ t.test('config list --json', t => { }) t.test('config delete no args', t => { - config(['delete'], (err) => { + config.exec(['delete'], (err) => { t.equal( err.message, 'usage instructions', @@ -202,7 +202,7 @@ t.test('config delete key', t => { t.equal(where, 'user', 'should save user config post-delete') } - config(['delete', 'foo'], (err) => { + config.exec(['delete', 'foo'], (err) => { t.ifError(err, 'npm config delete key') }) @@ -229,7 +229,7 @@ t.test('config delete multiple key', t => { t.equal(where, 'user', 'should save user config post-delete') } - config(['delete', 'foo', 'bar'], (err) => { + config.exec(['delete', 'foo', 'bar'], (err) => { t.ifError(err, 'npm config delete keys') }) @@ -252,7 +252,7 @@ t.test('config delete key --global', t => { } flatOptions.global = true - config(['delete', 'foo'], (err) => { + config.exec(['delete', 'foo'], (err) => { t.ifError(err, 'npm config delete key --global') }) @@ -264,7 +264,7 @@ t.test('config delete key --global', t => { }) t.test('config set no args', t => { - config(['set'], (err) => { + config.exec(['set'], (err) => { t.equal( err.message, 'usage instructions', @@ -287,7 +287,7 @@ t.test('config set key', t => { t.equal(where, 'user', 'should save user config') } - config(['set', 'foo', 'bar'], (err) => { + config.exec(['set', 'foo', 'bar'], (err) => { t.ifError(err, 'npm config set key') }) @@ -310,7 +310,7 @@ t.test('config set key=val', t => { t.equal(where, 'user', 'should save user config') } - config(['set', 'foo=bar'], (err) => { + config.exec(['set', 'foo=bar'], (err) => { t.ifError(err, 'npm config set key') }) @@ -341,7 +341,7 @@ t.test('config set multiple keys', t => { t.equal(where, 'user', 'should save user config') } - config(['set', ...args], (err) => { + config.exec(['set', ...args], (err) => { t.ifError(err, 'npm config set key') }) @@ -364,7 +364,7 @@ t.test('config set key to empty value', t => { t.equal(where, 'user', 'should save user config') } - config(['set', 'foo'], (err) => { + config.exec(['set', 'foo'], (err) => { t.ifError(err, 'npm config set key to empty value') }) @@ -392,7 +392,7 @@ t.test('config set invalid key', t => { delete npm.log.warn }) - config(['set', 'foo', 'bar'], (err) => { + config.exec(['set', 'foo', 'bar'], (err) => { t.ifError(err, 'npm config set invalid key') }) }) @@ -411,7 +411,7 @@ t.test('config set key --global', t => { } flatOptions.global = true - config(['set', 'foo', 'bar'], (err) => { + config.exec(['set', 'foo', 'bar'], (err) => { t.ifError(err, 'npm config set key --global') }) @@ -432,7 +432,7 @@ t.test('config get no args', t => { delete npm.config.find }) - config(['get'], (err) => { + config.exec(['get'], (err) => { t.ifError(err, 'npm config get no args') t.matchSnapshot(result, 'should list configs on config get no args') }) @@ -451,7 +451,7 @@ t.test('config get key', t => { throw new Error('should not save') } - config(['get', 'foo'], (err) => { + config.exec(['get', 'foo'], (err) => { t.ifError(err, 'npm config get key') }) @@ -479,7 +479,7 @@ t.test('config get multiple keys', t => { throw new Error('should not save') } - config(['get', 'foo', 'bar'], (err) => { + config.exec(['get', 'foo', 'bar'], (err) => { t.ifError(err, 'npm config get multiple keys') t.equal(result, 'foo=asdf\nbar=asdf') }) @@ -492,7 +492,7 @@ t.test('config get multiple keys', t => { }) t.test('config get private key', t => { - config(['get', '//private-reg.npmjs.org/:_authThoken'], (err) => { + config.exec(['get', '//private-reg.npmjs.org/:_authThoken'], (err) => { t.match( err, /The \/\/private-reg.npmjs.org\/:_authThoken option is protected, and cannot be retrieved in this way/, @@ -538,16 +538,19 @@ sign-git-commit=true` }, }, } - const config = requireInject('../../lib/config.js', editMocks) - config(['edit'], (err) => { + const Config = requireInject('../../lib/config.js', editMocks) + const config = new Config(npm) + + config.exec(['edit'], (err) => { t.ifError(err, 'npm config edit') // test no config file result editMocks.fs.readFile = (p, e, cb) => { cb(new Error('ERR')) } - const config = requireInject('../../lib/config.js', editMocks) - config(['edit'], (err) => { + const Config = requireInject('../../lib/config.js', editMocks) + const config = new Config(npm) + config.exec(['edit'], (err) => { t.ifError(err, 'npm config edit') }) }) @@ -594,8 +597,9 @@ t.test('config edit --global', t => { }, }, } - const config = requireInject('../../lib/config.js', editMocks) - config(['edit'], (err) => { + const Config = requireInject('../../lib/config.js', editMocks) + const config = new Config(npm) + config.exec(['edit'], (err) => { t.match(err, /exited with code: 137/, 'propagated exit code from editor') }) diff --git a/test/lib/dedupe.js b/test/lib/dedupe.js index b14185525..3e8b2f4c0 100644 --- a/test/lib/dedupe.js +++ b/test/lib/dedupe.js @@ -1,29 +1,29 @@ const { test } = require('tap') const requireInject = require('require-inject') -test('should throw in global mode', (t) => { - const dedupe = requireInject('../../lib/dedupe.js', { - '../../lib/npm.js': { - flatOptions: { - global: true, - }, +const npm = (base) => { + const config = base.config + return { + ...base, + flatOptions: { dryRun: false }, + config: { + get: (k) => config[k], }, - }) + } +} + +test('should throw in global mode', (t) => { + const Dedupe = requireInject('../../lib/dedupe.js') + const dedupe = new Dedupe(npm({ config: { global: true }})) - dedupe([], er => { + dedupe.exec([], er => { t.match(er, { code: 'EDEDUPEGLOBAL' }, 'throws EDEDUPEGLOBAL') t.end() }) }) test('should remove dupes using Arborist', (t) => { - const dedupe = requireInject('../../lib/dedupe.js', { - '../../lib/npm.js': { - prefix: 'foo', - flatOptions: { - dryRun: 'false', - }, - }, + const Dedupe = requireInject('../../lib/dedupe.js', { '@npmcli/arborist': function (args) { t.ok(args, 'gets options object') t.ok(args.path, 'gets path option') @@ -32,11 +32,17 @@ test('should remove dupes using Arborist', (t) => { t.ok(true, 'dedupe is called') } }, - '../../lib/utils/reify-finish.js': (arb) => { + '../../lib/utils/reify-finish.js': (npm, arb) => { t.ok(arb, 'gets arborist tree') }, }) - dedupe({ dryRun: true }, er => { + const dedupe = new Dedupe(npm({ + prefix: 'foo', + config: { + 'dry-run': 'true', + }, + })) + dedupe.exec([], er => { if (er) throw er t.ok(true, 'callback is called') @@ -45,20 +51,20 @@ test('should remove dupes using Arborist', (t) => { }) test('should remove dupes using Arborist - no arguments', (t) => { - const dedupe = requireInject('../../lib/dedupe.js', { - '../../lib/npm.js': { - prefix: 'foo', - flatOptions: { - dryRun: 'true', - }, - }, + const Dedupe = requireInject('../../lib/dedupe.js', { '@npmcli/arborist': function (args) { t.ok(args.dryRun, 'gets dryRun from flatOptions') this.dedupe = () => {} }, '../../lib/utils/reify-output.js': () => {}, }) - dedupe(null, () => { + const dedupe = new Dedupe(npm({ + prefix: 'foo', + config: { + 'dry-run': true, + }, + })) + dedupe.exec(null, () => { t.end() }) }) diff --git a/test/lib/deprecate.js b/test/lib/deprecate.js index fd563de12..03100166a 100644 --- a/test/lib/deprecate.js +++ b/test/lib/deprecate.js @@ -18,10 +18,7 @@ npmFetch.json = async (uri, opts) => { } } -const deprecate = requireInject('../../lib/deprecate.js', { - '../../lib/npm.js': { - flatOptions: { registry: 'https://registry.npmjs.org' }, - }, +const Deprecate = requireInject('../../lib/deprecate.js', { '../../lib/utils/get-identity.js': async () => getIdentityImpl(), '../../lib/utils/otplease.js': async (opts, fn) => fn(opts), libnpmaccess: { @@ -30,16 +27,19 @@ const deprecate = requireInject('../../lib/deprecate.js', { 'npm-registry-fetch': npmFetch, }) +const deprecate = new Deprecate({ + flatOptions: { registry: 'https://registry.npmjs.org' }, +}) + test('completion', async t => { const defaultIdentityImpl = getIdentityImpl t.teardown(() => { getIdentityImpl = defaultIdentityImpl }) - const { completion } = deprecate - const testComp = async (argv, expect) => { - const res = await completion({ conf: { argv: { remain: argv } } }) + const res = + await deprecate.completion({ conf: { argv: { remain: argv } } }) t.strictSame(res, expect, `completion: ${argv}`) } @@ -59,21 +59,21 @@ test('completion', async t => { }) test('no args', t => { - deprecate([], (err) => { + deprecate.exec([], (err) => { t.match(err, /Usage: npm deprecate/, 'logs usage') t.end() }) }) test('only one arg', t => { - deprecate(['foo'], (err) => { + deprecate.exec(['foo'], (err) => { t.match(err, /Usage: npm deprecate/, 'logs usage') t.end() }) }) test('invalid semver range', t => { - deprecate(['foo@notaversion', 'this will fail'], (err) => { + deprecate.exec(['foo@notaversion', 'this will fail'], (err) => { t.match(err, /invalid version range/, 'logs semver error') t.end() }) @@ -84,7 +84,7 @@ test('deprecates given range', t => { npmFetchBody = null }) - deprecate(['foo@1.0.0', 'this version is deprecated'], (err) => { + deprecate.exec(['foo@1.0.0', 'this version is deprecated'], (err) => { if (err) throw err @@ -110,7 +110,7 @@ test('deprecates all versions when no range is specified', t => { npmFetchBody = null }) - deprecate(['foo', 'this version is deprecated'], (err) => { + deprecate.exec(['foo', 'this version is deprecated'], (err) => { if (err) throw err diff --git a/test/lib/diff.js b/test/lib/diff.js index 926c54fdf..5e60f125c 100644 --- a/test/lib/diff.js +++ b/test/lib/diff.js @@ -28,7 +28,6 @@ const mocks = { npmlog: { info: noop, verbose: noop }, libnpmdiff: (...args) => libnpmdiff(...args), 'npm-registry-fetch': async () => ({}), - '../../lib/npm.js': npm, '../../lib/utils/output.js': noop, '../../lib/utils/read-local-package.js': async () => rlp(), '../../lib/utils/usage.js': () => 'usage instructions', @@ -42,7 +41,8 @@ t.afterEach(cb => { cb() }) -const diff = requireInject('../../lib/diff.js', mocks) +const Diff = requireInject('../../lib/diff.js', mocks) +const diff = new Diff(npm) t.test('no args', t => { t.test('in a project dir', t => { @@ -56,7 +56,7 @@ t.test('no args', t => { } npm.flatOptions.prefix = path - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -65,7 +65,7 @@ t.test('no args', t => { t.test('no args, missing package.json name in cwd', t => { rlp = () => undefined - diff([], err => { + diff.exec([], err => { t.match( err, /Needs multiple arguments to compare or run from a project dir./, @@ -80,7 +80,7 @@ t.test('no args', t => { throw new Error('ERR') } - diff([], err => { + diff.exec([], err => { t.match( err, /Needs multiple arguments to compare or run from a project dir./, @@ -106,7 +106,7 @@ t.test('single arg', t => { npm.flatOptions.diff = ['foo@1.0.0'] npm.flatOptions.prefix = path - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -120,7 +120,7 @@ t.test('single arg', t => { npm.flatOptions.diff = ['foo@1.0.0'] npm.flatOptions.prefix = path - diff([], err => { + diff.exec([], err => { t.match( err, /Needs multiple arguments to compare or run from a project dir./, @@ -142,7 +142,7 @@ t.test('single arg', t => { npm.flatOptions.diff = ['foo@~1.0.0'] npm.flatOptions.prefix = path - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -160,7 +160,7 @@ t.test('single arg', t => { npm.flatOptions.diff = ['2.1.4'] npm.flatOptions.prefix = path - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -172,7 +172,7 @@ t.test('single arg', t => { } npm.flatOptions.diff = ['2.1.4'] - diff([], err => { + diff.exec([], err => { t.match( err, /Needs multiple arguments to compare or run from a project dir./, @@ -200,7 +200,7 @@ t.test('single arg', t => { npm.flatOptions.diff = ['2.1.4'] npm.flatOptions.prefix = path - diff(['./foo.js', './bar.js'], err => { + diff.exec(['./foo.js', './bar.js'], err => { if (err) throw err }) @@ -224,7 +224,7 @@ t.test('single arg', t => { npm.flatOptions.diff = ['bar@1.0.0'] npm.flatOptions.prefix = path - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -250,7 +250,7 @@ t.test('single arg', t => { npm.flatOptions.diff = ['simple-output'] npm.flatOptions.prefix = path - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -264,7 +264,7 @@ t.test('single arg', t => { npm.flatOptions.diff = ['bar'] npm.flatOptions.prefix = path - diff([], err => { + diff.exec([], err => { t.match( err, /Needs multiple arguments to compare or run from a project dir./, @@ -297,7 +297,7 @@ t.test('single arg', t => { npm.flatOptions.diff = ['bar'] npm.flatOptions.prefix = path - const diff = requireInject('../../lib/diff.js', { + const Diff = requireInject('../../lib/diff.js', { ...mocks, pacote: { packument: (spec) => { @@ -313,8 +313,9 @@ t.test('single arg', t => { t.equal(b, 'bar@1.8.10', 'should have possible semver range spec') }, }) + const diff = new Diff(npm) - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -359,7 +360,7 @@ t.test('single arg', t => { npm.flatOptions.prefix = resolve(path, 'project') npm.globalDir = resolve(path, 'globalDir/lib/node_modules') - const diff = requireInject('../../lib/diff.js', { + const Diff = requireInject('../../lib/diff.js', { ...mocks, pacote: { packument: (spec) => { @@ -375,8 +376,9 @@ t.test('single arg', t => { t.equal(b, 'lorem@2.1.0', 'should have possible semver range spec') }, }) + const diff = new Diff(npm) - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -410,7 +412,7 @@ t.test('single arg', t => { npm.flatOptions.diff = ['bar@2.0.0'] npm.flatOptions.prefix = path - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -445,7 +447,7 @@ t.test('single arg', t => { }), }) - const diff = requireInject('../../lib/diff.js', { + const Diff = requireInject('../../lib/diff.js', { ...mocks, '../../lib/utils/read-local-package.js': async () => 'my-project', pacote: { @@ -462,11 +464,12 @@ t.test('single arg', t => { t.equal(b, 'lorem@2.2.2', 'should have expected target spec') }, }) + const diff = new Diff(npm) npm.flatOptions.diff = ['lorem'] npm.flatOptions.prefix = path - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -481,7 +484,7 @@ t.test('single arg', t => { }), }) - const diff = requireInject('../../lib/diff.js', { + const Diff = requireInject('../../lib/diff.js', { ...mocks, '../../lib/utils/read-local-package.js': async () => 'my-project', '@npmcli/arborist': class { @@ -494,11 +497,12 @@ t.test('single arg', t => { t.equal(b, `file:${path}`, 'should target current cwd') }, }) + const diff = new Diff(npm) npm.flatOptions.diff = ['lorem'] npm.flatOptions.prefix = path - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -517,7 +521,7 @@ t.test('single arg', t => { npm.flatOptions.diff = ['bar'] npm.flatOptions.prefix = path - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -535,7 +539,7 @@ t.test('single arg', t => { npm.flatOptions.diff = ['my-project'] npm.flatOptions.prefix = path - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -553,7 +557,7 @@ t.test('single arg', t => { npm.flatOptions.diff = ['/path/to/other-dir'] npm.flatOptions.prefix = path - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -564,7 +568,7 @@ t.test('single arg', t => { npm.flatOptions.diff = ['git+https://github.com/user/foo'] - diff([], err => { + diff.exec([], err => { t.match( err, /Spec type not supported./, @@ -588,7 +592,7 @@ t.test('first arg is a qualified spec', t => { } npm.flatOptions.diff = ['bar@1.0.0', 'bar@^2.0.0'] - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -622,7 +626,7 @@ t.test('first arg is a qualified spec', t => { npm.flatOptions.prefix = path npm.flatOptions.diff = ['bar@2.0.0', 'bar'] - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -638,7 +642,7 @@ t.test('first arg is a qualified spec', t => { t.equal(b, 'bar@2.0.0', 'should use name from first arg') } - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -653,7 +657,7 @@ t.test('first arg is a qualified spec', t => { } npm.flatOptions.diff = ['bar@1.0.0', 'bar-fork'] - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -691,7 +695,7 @@ t.test('first arg is a known dependency name', t => { npm.flatOptions.prefix = path npm.flatOptions.diff = ['bar', 'bar@2.0.0'] - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -731,7 +735,7 @@ t.test('first arg is a known dependency name', t => { npm.flatOptions.prefix = path npm.flatOptions.diff = ['bar', 'bar-fork'] - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -765,7 +769,7 @@ t.test('first arg is a known dependency name', t => { npm.flatOptions.prefix = path npm.flatOptions.diff = ['bar', '2.0.0'] - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -799,7 +803,7 @@ t.test('first arg is a known dependency name', t => { npm.flatOptions.prefix = path npm.flatOptions.diff = ['bar', 'bar-fork'] - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -819,7 +823,7 @@ t.test('first arg is a valid semver range', t => { t.equal(b, 'bar@2.0.0', 'should use expected spec') } - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -853,7 +857,7 @@ t.test('first arg is a valid semver range', t => { npm.flatOptions.prefix = path npm.flatOptions.diff = ['1.0.0', 'bar'] - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -869,7 +873,7 @@ t.test('first arg is a valid semver range', t => { } npm.flatOptions.diff = ['1.0.0', '2.0.0'] - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -883,7 +887,7 @@ t.test('first arg is a valid semver range', t => { npm.flatOptions.diff = ['1.0.0', '2.0.0'] npm.flatOptions.prefix = path - diff([], err => { + diff.exec([], err => { t.match( err, /Needs to be run from a project dir in order to diff two versions./, @@ -903,7 +907,7 @@ t.test('first arg is a valid semver range', t => { } npm.flatOptions.diff = ['1.0.0', 'bar'] - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -918,7 +922,7 @@ t.test('first arg is a valid semver range', t => { }), }) - const diff = requireInject('../../lib/diff.js', { + const Diff = requireInject('../../lib/diff.js', { ...mocks, '../../lib/utils/read-local-package.js': async () => 'my-project', '@npmcli/arborist': class { @@ -931,11 +935,12 @@ t.test('first arg is a valid semver range', t => { t.equal(b, 'lorem@2.0.0', 'should target expected spec') }, }) + const diff = new Diff(npm) npm.flatOptions.diff = ['1.0.0', 'lorem@2.0.0'] npm.flatOptions.prefix = path - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -955,7 +960,7 @@ t.test('first arg is an unknown dependency name', t => { } npm.flatOptions.diff = ['bar', 'bar@2.0.0'] - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -989,7 +994,7 @@ t.test('first arg is an unknown dependency name', t => { npm.flatOptions.prefix = path npm.flatOptions.diff = ['bar-fork', 'bar'] - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -1004,7 +1009,7 @@ t.test('first arg is an unknown dependency name', t => { } npm.flatOptions.diff = ['bar', '^1.0.0'] - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -1019,7 +1024,7 @@ t.test('first arg is an unknown dependency name', t => { } npm.flatOptions.diff = ['bar', 'bar-fork'] - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -1040,7 +1045,7 @@ t.test('first arg is an unknown dependency name', t => { npm.flatOptions.diff = ['bar', 'bar-fork'] npm.flatOptions.prefix = path - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -1062,7 +1067,7 @@ t.test('various options', t => { }, 'should forward nameOnly=true option') } - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -1085,7 +1090,7 @@ t.test('various options', t => { }, 'should forward diffFiles values') } - diff(['./foo.js', './bar.js'], err => { + diff.exec(['./foo.js', './bar.js'], err => { if (err) throw err }) @@ -1109,7 +1114,7 @@ t.test('various options', t => { } npm.flatOptions.prefix = path - diff(['./foo.js', './bar.js'], err => { + diff.exec(['./foo.js', './bar.js'], err => { if (err) throw err }) @@ -1137,7 +1142,7 @@ t.test('various options', t => { }, 'should forward diff options') } - diff([], err => { + diff.exec([], err => { if (err) throw err }) @@ -1148,7 +1153,7 @@ t.test('various options', t => { t.test('too many args', t => { npm.flatOptions.diff = ['a', 'b', 'c'] - diff([], err => { + diff.exec([], err => { t.match( err, /Can't use more than two --diff arguments./, diff --git a/test/lib/dist-tag.js b/test/lib/dist-tag.js index c18935230..b761fb103 100644 --- a/test/lib/dist-tag.js +++ b/test/lib/dist-tag.js @@ -48,7 +48,7 @@ const logger = (...msgs) => { log += '\n' } -const distTag = requireInject('../../lib/dist-tag.js', { +const DistTag = requireInject('../../lib/dist-tag.js', { npmlog: { error: logger, info: logger, @@ -58,26 +58,27 @@ const distTag = requireInject('../../lib/dist-tag.js', { get 'npm-registry-fetch' () { return npmRegistryFetchMock }, - '../../lib/npm.js': { - flatOptions: _flatOptions, - config: { - get (key) { - return _flatOptions[key] - }, - }, - }, '../../lib/utils/output.js': msg => { result = msg }, }) +const distTag = new DistTag({ + flatOptions: _flatOptions, + config: { + get (key) { + return _flatOptions[key] + }, + }, +}) + test('ls in current package', (t) => { prefix = t.testdir({ 'package.json': JSON.stringify({ name: '@scoped/pkg', }), }) - distTag(['ls'], (err) => { + distTag.exec(['ls'], (err) => { t.ifError(err, 'npm dist-tags ls') t.matchSnapshot( result, @@ -95,7 +96,7 @@ test('no args in current package', (t) => { name: '@scoped/pkg', }), }) - distTag([], (err) => { + distTag.exec([], (err) => { t.ifError(err, 'npm dist-tags ls') t.matchSnapshot( result, @@ -109,7 +110,7 @@ test('no args in current package', (t) => { test('borked cmd usage', (t) => { prefix = t.testdir({}) - distTag(['borked', '@scoped/pkg'], (err) => { + distTag.exec(['borked', '@scoped/pkg'], (err) => { t.matchSnapshot(err, 'should show usage error') result = '' log = '' @@ -119,7 +120,7 @@ test('borked cmd usage', (t) => { test('ls on named package', (t) => { prefix = t.testdir({}) - distTag(['ls', '@scoped/another'], (err) => { + distTag.exec(['ls', '@scoped/another'], (err) => { t.ifError(err, 'npm dist-tags ls') t.matchSnapshot( result, @@ -133,7 +134,7 @@ test('ls on named package', (t) => { test('ls on missing package', (t) => { prefix = t.testdir({}) - distTag(['ls', 'foo'], (err) => { + distTag.exec(['ls', 'foo'], (err) => { t.matchSnapshot( log, 'should log no dist-tag found msg' @@ -154,7 +155,7 @@ test('ls on missing name in current package', (t) => { version: '1.0.0', }), }) - distTag(['ls'], (err) => { + distTag.exec(['ls'], (err) => { t.matchSnapshot( err, 'should throw usage error message' @@ -167,7 +168,7 @@ test('ls on missing name in current package', (t) => { test('only named package arg', (t) => { prefix = t.testdir({}) - distTag(['@scoped/another'], (err) => { + distTag.exec(['@scoped/another'], (err) => { t.ifError(err, 'npm dist-tags ls') t.matchSnapshot( result, @@ -186,7 +187,7 @@ test('add new tag', (t) => { t.equal(opts.body, '7.7.7', 'should point to expected version') } prefix = t.testdir({}) - distTag(['add', '@scoped/another@7.7.7', 'c'], (err) => { + distTag.exec(['add', '@scoped/another@7.7.7', 'c'], (err) => { t.ifError(err, 'npm dist-tags add') t.matchSnapshot( result, @@ -201,7 +202,7 @@ test('add new tag', (t) => { test('add using valid semver range as name', (t) => { prefix = t.testdir({}) - distTag(['add', '@scoped/another@7.7.7', '1.0.0'], (err) => { + distTag.exec(['add', '@scoped/another@7.7.7', '1.0.0'], (err) => { t.match( err, /Error: Tag name must not be a valid SemVer range: 1.0.0/, @@ -219,7 +220,7 @@ test('add using valid semver range as name', (t) => { test('add missing args', (t) => { prefix = t.testdir({}) - distTag(['add', '@scoped/another@7.7.7'], (err) => { + distTag.exec(['add', '@scoped/another@7.7.7'], (err) => { t.matchSnapshot(err, 'should exit usage error message') result = '' log = '' @@ -229,7 +230,7 @@ test('add missing args', (t) => { test('add missing pkg name', (t) => { prefix = t.testdir({}) - distTag(['add', null], (err) => { + distTag.exec(['add', null], (err) => { t.matchSnapshot(err, 'should exit usage error message') result = '' log = '' @@ -239,7 +240,7 @@ test('add missing pkg name', (t) => { test('set existing version', (t) => { prefix = t.testdir({}) - distTag(['set', '@scoped/another@0.6.0', 'b'], (err) => { + distTag.exec(['set', '@scoped/another@0.6.0', 'b'], (err) => { t.ifError(err, 'npm dist-tags set') t.matchSnapshot( log, @@ -256,7 +257,7 @@ test('remove existing tag', (t) => { t.equal(opts.method, 'DELETE', 'should trigger request to remove tag') } prefix = t.testdir({}) - distTag(['rm', '@scoped/another', 'c'], (err) => { + distTag.exec(['rm', '@scoped/another', 'c'], (err) => { t.ifError(err, 'npm dist-tags rm') t.matchSnapshot(log, 'should log remove info') t.matchSnapshot(result, 'should return success msg') @@ -269,7 +270,7 @@ test('remove existing tag', (t) => { test('remove non-existing tag', (t) => { prefix = t.testdir({}) - distTag(['rm', '@scoped/another', 'nonexistent'], (err) => { + distTag.exec(['rm', '@scoped/another', 'nonexistent'], (err) => { t.match( err, /Error: nonexistent is not a dist-tag on @scoped\/another/, @@ -284,7 +285,7 @@ test('remove non-existing tag', (t) => { test('remove missing pkg name', (t) => { prefix = t.testdir({}) - distTag(['rm', null], (err) => { + distTag.exec(['rm', null], (err) => { t.matchSnapshot(err, 'should exit usage error message') result = '' log = '' diff --git a/test/lib/docs.js b/test/lib/docs.js index 8a59ed7cc..a7325738b 100644 --- a/test/lib/docs.js +++ b/test/lib/docs.js @@ -33,17 +33,18 @@ const pacote = { // keep a tally of which urls got opened const opened = {} -const openUrl = (url, errMsg, cb) => { +const openUrl = async (npm, url, errMsg) => { opened[url] = opened[url] || 0 opened[url]++ - process.nextTick(cb) } -const docs = requireInject('../../lib/docs.js', { +const Docs = requireInject('../../lib/docs.js', { pacote, '../../lib/utils/open-url.js': openUrl, }) +const docs = new Docs({ flatOptions: {} }) + t.test('open docs urls', t => { const expect = { nodocs: 'https://www.npmjs.com/package/nodocs', @@ -56,7 +57,7 @@ t.test('open docs urls', t => { t.plan(keys.length) keys.forEach(pkg => { t.test(pkg, t => { - docs([pkg], (er) => { + docs.exec([pkg], (er) => { if (er) throw er const url = expect[pkg] @@ -68,7 +69,7 @@ t.test('open docs urls', t => { }) t.test('open default package if none specified', t => { - docs([], (er) => { + docs.exec([], (er) => { if (er) throw er t.equal(opened['https://example.com'], 2, 'opened expected url', {opened}) diff --git a/test/lib/doctor.js b/test/lib/doctor.js index f5e6fd062..820049347 100644 --- a/test/lib/doctor.js +++ b/test/lib/doctor.js @@ -120,18 +120,18 @@ const cacache = { }, } -const doctor = requireInject('../../lib/doctor.js', { +const Doctor = requireInject('../../lib/doctor.js', { '../../lib/utils/is-windows.js': false, '../../lib/utils/ping.js': ping, '../../lib/utils/output.js': (data) => { output.push(data) }, - '../../lib/npm.js': npm, cacache, pacote, 'make-fetch-happen': fetch, which, }) +const doctor = new Doctor(npm) const origVersion = process.version test('node versions', t => { @@ -162,7 +162,7 @@ test('node versions', t => { clearLogs() }) - doctor([], (err) => { + doctor.exec([], (err) => { if (err) { st.fail(output) return st.end() @@ -211,7 +211,7 @@ test('node versions', t => { clearLogs() }) - doctor([], (err) => { + doctor.exec([], (err) => { if (err) { st.fail(err) return st.end() @@ -255,7 +255,7 @@ test('node versions', t => { clearLogs() }) - doctor([], (err) => { + doctor.exec([], (err) => { st.match(err, /Some problems found/, 'detected the ping error') st.match(logs, { checkPing: { finished: true }, @@ -282,18 +282,18 @@ test('node versions', t => { }) vt.test('npm doctor skips some tests in windows', st => { - const winDoctor = requireInject('../../lib/doctor.js', { + const WinDoctor = requireInject('../../lib/doctor.js', { '../../lib/utils/is-windows.js': true, '../../lib/utils/ping.js': ping, '../../lib/utils/output.js': (data) => { output.push(data) }, - '../../lib/npm.js': npm, cacache, pacote, 'make-fetch-happen': fetch, which, }) + const winDoctor = new WinDoctor(npm) const dir = st.testdir() npm.cache = npm.flatOptions.cache = dir @@ -312,7 +312,7 @@ test('node versions', t => { clearLogs() }) - winDoctor([], (err) => { + winDoctor.exec([], (err) => { if (err) { st.fail(output) return st.end() @@ -360,7 +360,7 @@ test('node versions', t => { clearLogs() }) - doctor([], (err) => { + doctor.exec([], (err) => { st.match(err, /Some problems found/, 'detected the ping error') st.match(logs, { checkPing: { finished: true }, @@ -409,7 +409,7 @@ test('node versions', t => { clearLogs() }) - doctor([], (err) => { + doctor.exec([], (err) => { st.match(err, /Some problems found/, 'detected the ping error') st.match(logs, { checkPing: { finished: true }, @@ -458,7 +458,7 @@ test('node versions', t => { clearLogs() }) - doctor([], (err) => { + doctor.exec([], (err) => { st.match(err, /Some problems found/, 'detected the out of date npm') st.match(logs, { checkPing: { finished: true }, @@ -563,19 +563,19 @@ test('node versions', t => { } } - const doctor = requireInject('../../lib/doctor.js', { + const Doctor = requireInject('../../lib/doctor.js', { '../../lib/utils/is-windows.js': false, '../../lib/utils/ping.js': ping, '../../lib/utils/output.js': (data) => { output.push(data) }, - '../../lib/npm.js': npm, cacache, pacote, 'make-fetch-happen': fetch, which, fs, }) + const doctor = new Doctor(npm) // it's necessary to allow tests in node 10.x to not mark 12.x as lted npm.cache = npm.flatOptions.cache = join(dir, 'cache') @@ -600,7 +600,7 @@ test('node versions', t => { clearLogs() }) - doctor([], (err) => { + doctor.exec([], (err) => { st.match(err, /Some problems found/, 'identified problems') st.match(logs, { checkPing: { finished: true }, @@ -653,7 +653,7 @@ test('node versions', t => { clearLogs() }) - doctor([], (err) => { + doctor.exec([], (err) => { st.match(err, /Some problems found/, 'detected the missing git') st.match(logs, { checkPing: { finished: true }, @@ -706,7 +706,7 @@ test('node versions', t => { clearLogs() }) - doctor([], (err) => { + doctor.exec([], (err) => { // cache verification problems get fixed and so do not throw an error if (err) { st.fail(output) @@ -765,7 +765,7 @@ test('node versions', t => { clearLogs() }) - doctor([], (err) => { + doctor.exec([], (err) => { // cache verification problems get fixed and so do not throw an error if (err) { st.fail(output) @@ -823,7 +823,7 @@ test('node versions', t => { clearLogs() }) - doctor([], (err) => { + doctor.exec([], (err) => { // cache verification problems get fixed and so do not throw an error if (err) { st.fail(output) @@ -878,7 +878,7 @@ test('node versions', t => { clearLogs() }) - doctor([], (err) => { + doctor.exec([], (err) => { // cache verification problems get fixed and so do not throw an error st.match(err, /Some problems found/, 'detected the non-default registry') st.match(logs, { @@ -942,7 +942,7 @@ test('outdated node version', vt => { clearLogs() }) - doctor([], (err) => { + doctor.exec([], (err) => { st.match(err, /Some problems found/, 'detected the out of date nodejs') st.match(logs, { checkPing: { finished: true }, diff --git a/test/lib/edit.js b/test/lib/edit.js index 0d3bbb4c5..acf03fa43 100644 --- a/test/lib/edit.js +++ b/test/lib/edit.js @@ -23,6 +23,7 @@ const childProcess = { } let rebuildArgs = null +let rebuildFail = null let EDITOR = 'vim' const npm = { config: { @@ -32,17 +33,17 @@ const npm = { commands: { rebuild: (args, cb) => { rebuildArgs = args - return cb() + return cb(rebuildFail) }, }, } const gracefulFs = require('graceful-fs') -const edit = requireInject('../../lib/edit.js', { - '../../lib/npm.js': npm, +const Edit = requireInject('../../lib/edit.js', { child_process: childProcess, 'graceful-fs': gracefulFs, }) +const edit = new Edit(npm) test('npm edit', t => { t.teardown(() => { @@ -52,7 +53,7 @@ test('npm edit', t => { editorOpts = null }) - return edit(['semver'], (err) => { + return edit.exec(['semver'], (err) => { if (err) throw err @@ -65,6 +66,27 @@ test('npm edit', t => { }) }) +test('rebuild fails', t => { + t.teardown(() => { + rebuildFail = null + rebuildArgs = null + editorBin = null + editorArgs = null + editorOpts = null + }) + + rebuildFail = new Error('test error') + return edit.exec(['semver'], (err) => { + const path = resolve(__dirname, '../../node_modules/semver') + t.strictSame(editorBin, EDITOR, 'used the correct editor') + t.strictSame(editorArgs, [path], 'edited the correct directory') + t.strictSame(editorOpts, { stdio: 'inherit' }, 'passed the correct opts') + t.strictSame(rebuildArgs, [path], 'passed the correct path to rebuild') + t.match(err, { message: 'test error' }) + t.end() + }) +}) + test('npm edit editor has flags', t => { EDITOR = 'code -w' t.teardown(() => { @@ -75,7 +97,7 @@ test('npm edit editor has flags', t => { EDITOR = 'vim' }) - return edit(['semver'], (err) => { + return edit.exec(['semver'], (err) => { if (err) throw err @@ -89,7 +111,7 @@ test('npm edit editor has flags', t => { }) test('npm edit no args', t => { - return edit([], (err) => { + return edit.exec([], (err) => { t.match(err, /npm edit/, 'throws usage error') t.end() }) @@ -104,7 +126,7 @@ test('npm edit lstat error propagates', t => { gracefulFs.lstat = _lstat }) - return edit(['semver'], (err) => { + return edit.exec(['semver'], (err) => { t.match(err, /lstat failed/, 'user received correct error') t.end() }) @@ -116,7 +138,7 @@ test('npm edit editor exit code error propagates', t => { EDITOR_CODE = 0 }) - return edit(['semver'], (err) => { + return edit.exec(['semver'], (err) => { t.match(err, /exited with code: 137/, 'user received correct error') t.end() }) diff --git a/test/lib/exec.js b/test/lib/exec.js index ac813ade7..4dc7f31cc 100644 --- a/test/lib/exec.js +++ b/test/lib/exec.js @@ -90,13 +90,13 @@ const mocks = { '@npmcli/arborist': Arborist, '@npmcli/run-script': runScript, '@npmcli/ci-detect': () => CI_NAME, - '../../lib/npm.js': npm, pacote, read, 'mkdirp-infer-owner': mkdirp, '../../lib/utils/output.js': output, } -const exec = requireInject('../../lib/exec.js', mocks) +const Exec = requireInject('../../lib/exec.js', mocks) +const exec = new Exec(npm) t.afterEach(cb => { MKDIRPS.length = 0 @@ -116,7 +116,7 @@ t.afterEach(cb => { cb() }) -t.test('npx foo, bin already exists locally', async t => { +t.test('npx foo, bin already exists locally', t => { const path = t.testdir({ foo: 'just some file', }) @@ -124,24 +124,25 @@ t.test('npx foo, bin already exists locally', async t => { PROGRESS_IGNORED = true npm.localBin = path - await exec(['foo', 'one arg', 'two arg'], er => { + exec.exec(['foo', 'one arg', 'two arg'], er => { t.ifError(er, 'npm exec') + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'foo' }}, + args: ['one arg', 'two arg'], + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { + PATH: [path, ...PATH].join(delimiter), + }, + stdio: 'inherit', + }]) + t.end() }) - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'foo' }}, - args: ['one arg', 'two arg'], - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { - PATH: [path, ...PATH].join(delimiter), - }, - stdio: 'inherit', - }]) }) -t.test('npx foo, bin already exists globally', async t => { +t.test('npx foo, bin already exists globally', t => { const path = t.testdir({ foo: 'just some file', }) @@ -149,24 +150,25 @@ t.test('npx foo, bin already exists globally', async t => { PROGRESS_IGNORED = true npm.globalBin = path - await exec(['foo', 'one arg', 'two arg'], er => { + exec.exec(['foo', 'one arg', 'two arg'], er => { t.ifError(er, 'npm exec') + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'foo' }}, + args: ['one arg', 'two arg'], + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { + PATH: [path, ...PATH].join(delimiter), + }, + stdio: 'inherit', + }]) + t.end() }) - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'foo' }}, - args: ['one arg', 'two arg'], - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { - PATH: [path, ...PATH].join(delimiter), - }, - stdio: 'inherit', - }]) }) -t.test('npm exec foo, already present locally', async t => { +t.test('npm exec foo, already present locally', t => { const path = t.testdir() npm.localPrefix = path ARB_ACTUAL_TREE[path] = { @@ -180,94 +182,103 @@ t.test('npm exec foo, already present locally', async t => { }, _from: 'foo@', } - await exec(['foo', 'one arg', 'two arg'], er => { + exec.exec(['foo', 'one arg', 'two arg'], er => { if (er) throw er + t.strictSame(MKDIRPS, [], 'no need to make any dirs') + t.match(ARB_CTOR, [{ package: ['foo'], path }]) + t.strictSame(ARB_REIFY, [], 'no need to reify anything') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'foo' } }, + args: ['one arg', 'two arg'], + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { PATH: process.env.PATH }, + stdio: 'inherit', + }]) + t.end() }) - t.strictSame(MKDIRPS, [], 'no need to make any dirs') - t.match(ARB_CTOR, [{ package: ['foo'], path }]) - t.strictSame(ARB_REIFY, [], 'no need to reify anything') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'foo' } }, - args: ['one arg', 'two arg'], - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { PATH: process.env.PATH }, - stdio: 'inherit', - }]) }) -t.test('npm exec <noargs>, run interactive shell', async t => { +t.test('npm exec <noargs>, run interactive shell', t => { CI_NAME = null const { isTTY } = process.stdin process.stdin.isTTY = true t.teardown(() => process.stdin.isTTY = isTTY) - const run = async (t, doRun = true) => { + const run = (t, doRun, cb) => { LOG_WARN.length = 0 ARB_CTOR.length = 0 MKDIRPS.length = 0 ARB_REIFY.length = 0 OUTPUT.length = 0 - await exec([], er => { + exec.exec([], er => { if (er) throw er + t.strictSame(MKDIRPS, [], 'no need to make any dirs') + t.strictSame(ARB_CTOR, [], 'no need to instantiate arborist') + t.strictSame(ARB_REIFY, [], 'no need to reify anything') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + if (doRun) { + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'shell-cmd' } }, + args: [], + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { PATH: process.env.PATH }, + stdio: 'inherit', + }]) + } else + t.strictSame(RUN_SCRIPTS, []) + + RUN_SCRIPTS.length = 0 + cb() }) - t.strictSame(MKDIRPS, [], 'no need to make any dirs') - t.strictSame(ARB_CTOR, [], 'no need to instantiate arborist') - t.strictSame(ARB_REIFY, [], 'no need to reify anything') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - if (doRun) { - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'shell-cmd' } }, - args: [], - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { PATH: process.env.PATH }, - stdio: 'inherit', - }]) - } else - t.strictSame(RUN_SCRIPTS, []) - RUN_SCRIPTS.length = 0 } - t.test('print message when tty and not in CI', async t => { + t.test('print message when tty and not in CI', t => { CI_NAME = null process.stdin.isTTY = true - await run(t) - t.strictSame(LOG_WARN, []) - t.strictSame(OUTPUT, [ - ['\nEntering npm script environment\nType \'exit\' or ^D when finished\n'], - ], 'printed message about interactive shell') + run(t, true, () => { + t.strictSame(LOG_WARN, []) + t.strictSame(OUTPUT, [ + ['\nEntering npm script environment\nType \'exit\' or ^D when finished\n'], + ], 'printed message about interactive shell') + t.end() + }) }) - t.test('no message when not TTY', async t => { + t.test('no message when not TTY', t => { CI_NAME = null process.stdin.isTTY = false - await run(t) - t.strictSame(LOG_WARN, []) - t.strictSame(OUTPUT, [], 'no message about interactive shell') + run(t, true, () => { + t.strictSame(LOG_WARN, []) + t.strictSame(OUTPUT, [], 'no message about interactive shell') + t.end() + }) }) - t.test('print warning when in CI and interactive', async t => { + t.test('print warning when in CI and interactive', t => { CI_NAME = 'travis-ci' process.stdin.isTTY = true - await run(t, false) - t.strictSame(LOG_WARN, [ - ['exec', 'Interactive mode disabled in CI environment'], - ]) - t.strictSame(OUTPUT, [], 'no message about interactive shell') + run(t, false, () => { + t.strictSame(LOG_WARN, [ + ['exec', 'Interactive mode disabled in CI environment'], + ]) + t.strictSame(OUTPUT, [], 'no message about interactive shell') + t.end() + }) }) t.end() }) -t.test('npm exec foo, not present locally or in central loc', async t => { +t.test('npm exec foo, not present locally or in central loc', t => { const path = t.testdir() const installDir = resolve('cache-dir/_npx/f7fbba6e0636f890') npm.localPrefix = path @@ -285,28 +296,29 @@ t.test('npm exec foo, not present locally or in central loc', async t => { }, _from: 'foo@', } - await exec(['foo', 'one arg', 'two arg'], er => { + exec.exec(['foo', 'one arg', 'two arg'], er => { if (er) throw er + t.strictSame(MKDIRPS, [installDir], 'need to make install dir') + t.match(ARB_CTOR, [{ package: ['foo'], path }]) + t.match(ARB_REIFY, [{add: ['foo@'], legacyPeerDeps: false}], 'need to install foo@') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'foo' } }, + args: ['one arg', 'two arg'], + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { PATH }, + stdio: 'inherit', + }]) + t.end() }) - t.strictSame(MKDIRPS, [installDir], 'need to make install dir') - t.match(ARB_CTOR, [{ package: ['foo'], path }]) - t.match(ARB_REIFY, [{add: ['foo@'], legacyPeerDeps: false}], 'need to install foo@') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'foo' } }, - args: ['one arg', 'two arg'], - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { PATH }, - stdio: 'inherit', - }]) }) -t.test('npm exec foo, not present locally but in central loc', async t => { +t.test('npm exec foo, not present locally but in central loc', t => { const path = t.testdir() const installDir = resolve('cache-dir/_npx/f7fbba6e0636f890') npm.localPrefix = path @@ -324,28 +336,29 @@ t.test('npm exec foo, not present locally but in central loc', async t => { }, _from: 'foo@', } - await exec(['foo', 'one arg', 'two arg'], er => { + exec.exec(['foo', 'one arg', 'two arg'], er => { if (er) throw er + t.strictSame(MKDIRPS, [installDir], 'need to make install dir') + t.match(ARB_CTOR, [{ package: ['foo'], path }]) + t.match(ARB_REIFY, [], 'no need to install again, already there') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'foo' } }, + args: ['one arg', 'two arg'], + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { PATH }, + stdio: 'inherit', + }]) + t.end() }) - t.strictSame(MKDIRPS, [installDir], 'need to make install dir') - t.match(ARB_CTOR, [{ package: ['foo'], path }]) - t.match(ARB_REIFY, [], 'no need to install again, already there') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'foo' } }, - args: ['one arg', 'two arg'], - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { PATH }, - stdio: 'inherit', - }]) }) -t.test('npm exec foo, present locally but wrong version', async t => { +t.test('npm exec foo, present locally but wrong version', t => { const path = t.testdir() const installDir = resolve('cache-dir/_npx/2badf4630f1cfaad') npm.localPrefix = path @@ -363,28 +376,29 @@ t.test('npm exec foo, present locally but wrong version', async t => { }, _from: 'foo@2.x', } - await exec(['foo@2.x', 'one arg', 'two arg'], er => { + exec.exec(['foo@2.x', 'one arg', 'two arg'], er => { if (er) throw er + t.strictSame(MKDIRPS, [installDir], 'need to make install dir') + t.match(ARB_CTOR, [{ package: ['foo'], path }]) + t.match(ARB_REIFY, [{ add: ['foo@2.x'], legacyPeerDeps: false }], 'need to add foo@2.x') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'foo' } }, + args: ['one arg', 'two arg'], + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { PATH }, + stdio: 'inherit', + }]) + t.end() }) - t.strictSame(MKDIRPS, [installDir], 'need to make install dir') - t.match(ARB_CTOR, [{ package: ['foo'], path }]) - t.match(ARB_REIFY, [{ add: ['foo@2.x'], legacyPeerDeps: false }], 'need to add foo@2.x') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'foo' } }, - args: ['one arg', 'two arg'], - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { PATH }, - stdio: 'inherit', - }]) }) -t.test('npm exec --package=foo bar', async t => { +t.test('npm exec --package=foo bar', t => { const path = t.testdir() npm.localPrefix = path ARB_ACTUAL_TREE[path] = { @@ -399,27 +413,28 @@ t.test('npm exec --package=foo bar', async t => { _from: 'foo@', } npm.flatOptions.package = ['foo'] - await exec(['bar', 'one arg', 'two arg'], er => { + exec.exec(['bar', 'one arg', 'two arg'], er => { if (er) throw er + t.strictSame(MKDIRPS, [], 'no need to make any dirs') + t.match(ARB_CTOR, [{ package: ['foo'], path }]) + t.strictSame(ARB_REIFY, [], 'no need to reify anything') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'bar' } }, + args: ['one arg', 'two arg'], + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { PATH: process.env.PATH }, + stdio: 'inherit', + }]) + t.end() }) - t.strictSame(MKDIRPS, [], 'no need to make any dirs') - t.match(ARB_CTOR, [{ package: ['foo'], path }]) - t.strictSame(ARB_REIFY, [], 'no need to reify anything') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'bar' } }, - args: ['one arg', 'two arg'], - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { PATH: process.env.PATH }, - stdio: 'inherit', - }]) }) -t.test('npm exec @foo/bar -- --some=arg, locally installed', async t => { +t.test('npm exec @foo/bar -- --some=arg, locally installed', t => { const foobarManifest = { name: '@foo/bar', version: '1.2.3', @@ -440,27 +455,28 @@ t.test('npm exec @foo/bar -- --some=arg, locally installed', async t => { children: new Map([['@foo/bar', { name: '@foo/bar', version: '1.2.3' }]]), } MANIFESTS['@foo/bar'] = foobarManifest - await exec(['@foo/bar', '--some=arg'], er => { + exec.exec(['@foo/bar', '--some=arg'], er => { if (er) throw er + t.strictSame(MKDIRPS, [], 'no need to make any dirs') + t.match(ARB_CTOR, [{ package: ['@foo/bar'], path }]) + t.strictSame(ARB_REIFY, [], 'no need to reify anything') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'bar' } }, + args: ['--some=arg'], + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { PATH: process.env.PATH }, + stdio: 'inherit', + }]) + t.end() }) - t.strictSame(MKDIRPS, [], 'no need to make any dirs') - t.match(ARB_CTOR, [{ package: ['@foo/bar'], path }]) - t.strictSame(ARB_REIFY, [], 'no need to reify anything') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'bar' } }, - args: ['--some=arg'], - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { PATH: process.env.PATH }, - stdio: 'inherit', - }]) }) -t.test('npm exec @foo/bar, with same bin alias and no unscoped named bin, locally installed', async t => { +t.test('npm exec @foo/bar, with same bin alias and no unscoped named bin, locally installed', t => { const foobarManifest = { name: '@foo/bar', version: '1.2.3', @@ -482,24 +498,25 @@ t.test('npm exec @foo/bar, with same bin alias and no unscoped named bin, locall children: new Map([['@foo/bar', { name: '@foo/bar', version: '1.2.3' }]]), } MANIFESTS['@foo/bar'] = foobarManifest - await exec(['@foo/bar', 'one arg', 'two arg'], er => { + exec.exec(['@foo/bar', 'one arg', 'two arg'], er => { if (er) throw er + t.strictSame(MKDIRPS, [], 'no need to make any dirs') + t.match(ARB_CTOR, [{ package: ['@foo/bar'], path }]) + t.strictSame(ARB_REIFY, [], 'no need to reify anything') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'baz' } }, + args: ['one arg', 'two arg'], + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { PATH: process.env.PATH }, + stdio: 'inherit', + }]) + t.end() }) - t.strictSame(MKDIRPS, [], 'no need to make any dirs') - t.match(ARB_CTOR, [{ package: ['@foo/bar'], path }]) - t.strictSame(ARB_REIFY, [], 'no need to reify anything') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'baz' } }, - args: ['one arg', 'two arg'], - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { PATH: process.env.PATH }, - stdio: 'inherit', - }]) }) t.test('npm exec @foo/bar, with different bin alias and no unscoped named bin, locally installed', t => { @@ -519,12 +536,12 @@ t.test('npm exec @foo/bar, with different bin alias and no unscoped named bin, l _from: 'foo@', _id: '@foo/bar@1.2.3', } - return t.rejects(exec(['@foo/bar'], er => { - if (er) - throw er - }), { - message: 'could not determine executable to run', - pkgid: '@foo/bar@1.2.3', + exec.exec(['@foo/bar'], er => { + t.match(er, { + message: 'could not determine executable to run', + pkgid: '@foo/bar@1.2.3', + }) + t.end() }) }) @@ -534,7 +551,7 @@ t.test('run command with 2 packages, need install, verify sort', t => { const cases = [['foo', 'bar'], ['bar', 'foo']] t.plan(cases.length) for (const packages of cases) { - t.test(packages.join(', '), async t => { + t.test(packages.join(', '), t => { npm.flatOptions.package = packages const add = packages.map(p => `${p}@`).sort((a, b) => a.localeCompare(b)) const path = t.testdir() @@ -562,25 +579,26 @@ t.test('run command with 2 packages, need install, verify sort', t => { }, _from: 'bar@', } - await exec(['foobar', 'one arg', 'two arg'], er => { + exec.exec(['foobar', 'one arg', 'two arg'], er => { if (er) throw er + t.strictSame(MKDIRPS, [installDir], 'need to make install dir') + t.match(ARB_CTOR, [{ package: packages, path }]) + t.match(ARB_REIFY, [{add, legacyPeerDeps: false}], 'need to install both packages') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'foobar' } }, + args: ['one arg', 'two arg'], + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { PATH }, + stdio: 'inherit', + }]) + t.end() }) - t.strictSame(MKDIRPS, [installDir], 'need to make install dir') - t.match(ARB_CTOR, [{ package: packages, path }]) - t.match(ARB_REIFY, [{add, legacyPeerDeps: false}], 'need to install both packages') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'foobar' } }, - args: ['one arg', 'two arg'], - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { PATH }, - stdio: 'inherit', - }]) }) } }) @@ -597,12 +615,12 @@ t.test('npm exec foo, no bin in package', t => { _from: 'foo@', _id: 'foo@1.2.3', } - return t.rejects(exec(['foo'], er => { - if (er) - throw er - }), { - message: 'could not determine executable to run', - pkgid: 'foo@1.2.3', + exec.exec(['foo'], er => { + t.match(er, { + message: 'could not determine executable to run', + pkgid: 'foo@1.2.3', + }) + t.end() }) }) @@ -622,16 +640,16 @@ t.test('npm exec foo, many bins in package, none named foo', t => { _from: 'foo@', _id: 'foo@1.2.3', } - return t.rejects(exec(['foo'], er => { - if (er) - throw er - }), { - message: 'could not determine executable to run', - pkgid: 'foo@1.2.3', + exec.exec(['foo'], er => { + t.match(er, { + message: 'could not determine executable to run', + pkgid: 'foo@1.2.3', + }) + t.end() }) }) -t.test('npm exec -p foo -c "ls -laF"', async t => { +t.test('npm exec -p foo -c "ls -laF"', t => { const path = t.testdir() npm.localPrefix = path npm.flatOptions.package = ['foo'] @@ -644,31 +662,35 @@ t.test('npm exec -p foo -c "ls -laF"', async t => { version: '1.2.3', _from: 'foo@', } - await exec([], er => { + exec.exec([], er => { if (er) throw er + t.strictSame(MKDIRPS, [], 'no need to make any dirs') + t.match(ARB_CTOR, [{ package: ['foo'], path }]) + t.strictSame(ARB_REIFY, [], 'no need to reify anything') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'ls -laF' } }, + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { PATH: process.env.PATH }, + stdio: 'inherit', + }]) + t.end() }) - t.strictSame(MKDIRPS, [], 'no need to make any dirs') - t.match(ARB_CTOR, [{ package: ['foo'], path }]) - t.strictSame(ARB_REIFY, [], 'no need to reify anything') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'ls -laF' } }, - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { PATH: process.env.PATH }, - stdio: 'inherit', - }]) }) t.test('positional args and --call together is an error', t => { npm.flatOptions.call = 'true' - return exec(['foo'], er => t.equal(er, exec.usage)) + exec.exec(['foo'], er => { + t.equal(er, exec.usage) + t.end() + }) }) -t.test('prompt when installs are needed if not already present and shell is a TTY', async t => { +t.test('prompt when installs are needed if not already present and shell is a TTY', t => { const stdoutTTY = process.stdout.isTTY const stdinTTY = process.stdin.isTTY t.teardown(() => { @@ -712,31 +734,32 @@ t.test('prompt when installs are needed if not already present and shell is a TT }, _from: 'bar@', } - await exec(['foobar'], er => { + exec.exec(['foobar'], er => { if (er) throw er + t.strictSame(MKDIRPS, [installDir], 'need to make install dir') + t.match(ARB_CTOR, [{ package: packages, path }]) + t.match(ARB_REIFY, [{add, legacyPeerDeps: false}], 'need to install both packages') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'foobar' } }, + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { PATH }, + stdio: 'inherit', + }]) + t.strictSame(READ, [{ + prompt: 'Need to install the following packages:\n bar\n foo\nOk to proceed? ', + default: 'y', + }]) + t.end() }) - t.strictSame(MKDIRPS, [installDir], 'need to make install dir') - t.match(ARB_CTOR, [{ package: packages, path }]) - t.match(ARB_REIFY, [{add, legacyPeerDeps: false}], 'need to install both packages') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'foobar' } }, - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { PATH }, - stdio: 'inherit', - }]) - t.strictSame(READ, [{ - prompt: 'Need to install the following packages:\n bar\n foo\nOk to proceed? ', - default: 'y', - }]) }) -t.test('skip prompt when installs are needed if not already present and shell is not a tty (multiple packages)', async t => { +t.test('skip prompt when installs are needed if not already present and shell is not a tty (multiple packages)', t => { const stdoutTTY = process.stdout.isTTY const stdinTTY = process.stdin.isTTY t.teardown(() => { @@ -780,29 +803,30 @@ t.test('skip prompt when installs are needed if not already present and shell is }, _from: 'bar@', } - await exec(['foobar'], er => { + exec.exec(['foobar'], er => { if (er) throw er + t.strictSame(MKDIRPS, [installDir], 'need to make install dir') + t.match(ARB_CTOR, [{ package: packages, path }]) + t.match(ARB_REIFY, [{add, legacyPeerDeps: false}], 'need to install both packages') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'foobar' } }, + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { PATH }, + stdio: 'inherit', + }]) + t.strictSame(READ, [], 'should not have prompted') + t.strictSame(LOG_WARN, [['exec', 'The following packages were not found and will be installed: bar, foo']], 'should have printed a warning') + t.end() }) - t.strictSame(MKDIRPS, [installDir], 'need to make install dir') - t.match(ARB_CTOR, [{ package: packages, path }]) - t.match(ARB_REIFY, [{add, legacyPeerDeps: false}], 'need to install both packages') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'foobar' } }, - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { PATH }, - stdio: 'inherit', - }]) - t.strictSame(READ, [], 'should not have prompted') - t.strictSame(LOG_WARN, [['exec', 'The following packages were not found and will be installed: bar, foo']], 'should have printed a warning') }) -t.test('skip prompt when installs are needed if not already present and shell is not a tty (single package)', async t => { +t.test('skip prompt when installs are needed if not already present and shell is not a tty (single package)', t => { const stdoutTTY = process.stdout.isTTY const stdinTTY = process.stdin.isTTY t.teardown(() => { @@ -838,29 +862,30 @@ t.test('skip prompt when installs are needed if not already present and shell is }, _from: 'foo@', } - await exec(['foobar'], er => { + exec.exec(['foobar'], er => { if (er) throw er + t.strictSame(MKDIRPS, [installDir], 'need to make install dir') + t.match(ARB_CTOR, [{ package: packages, path }]) + t.match(ARB_REIFY, [{add, legacyPeerDeps: false}], 'need to install the package') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'foobar' } }, + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { PATH }, + stdio: 'inherit', + }]) + t.strictSame(READ, [], 'should not have prompted') + t.strictSame(LOG_WARN, [['exec', 'The following package was not found and will be installed: foo']], 'should have printed a warning') + t.end() }) - t.strictSame(MKDIRPS, [installDir], 'need to make install dir') - t.match(ARB_CTOR, [{ package: packages, path }]) - t.match(ARB_REIFY, [{add, legacyPeerDeps: false}], 'need to install the package') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'foobar' } }, - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { PATH }, - stdio: 'inherit', - }]) - t.strictSame(READ, [], 'should not have prompted') - t.strictSame(LOG_WARN, [['exec', 'The following package was not found and will be installed: foo']], 'should have printed a warning') }) -t.test('abort if prompt rejected', async t => { +t.test('abort if prompt rejected', t => { const stdoutTTY = process.stdout.isTTY const stdinTTY = process.stdin.isTTY t.teardown(() => { @@ -903,21 +928,22 @@ t.test('abort if prompt rejected', async t => { }, _from: 'bar@', } - await exec(['foobar'], er => { + exec.exec(['foobar'], er => { t.equal(er, 'canceled', 'should be canceled') + t.strictSame(MKDIRPS, [installDir], 'need to make install dir') + t.match(ARB_CTOR, [{ package: packages, path }]) + t.strictSame(ARB_REIFY, [], 'no install performed') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + t.strictSame(RUN_SCRIPTS, []) + t.strictSame(READ, [{ + prompt: 'Need to install the following packages:\n bar\n foo\nOk to proceed? ', + default: 'y', + }]) + t.end() }) - t.strictSame(MKDIRPS, [installDir], 'need to make install dir') - t.match(ARB_CTOR, [{ package: packages, path }]) - t.strictSame(ARB_REIFY, [], 'no install performed') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - t.strictSame(RUN_SCRIPTS, []) - t.strictSame(READ, [{ - prompt: 'Need to install the following packages:\n bar\n foo\nOk to proceed? ', - default: 'y', - }]) }) -t.test('abort if prompt false', async t => { +t.test('abort if prompt false', t => { const stdoutTTY = process.stdout.isTTY const stdinTTY = process.stdin.isTTY t.teardown(() => { @@ -960,21 +986,22 @@ t.test('abort if prompt false', async t => { }, _from: 'bar@', } - await exec(['foobar'], er => { + exec.exec(['foobar'], er => { t.equal(er, 'canceled', 'should be canceled') + t.strictSame(MKDIRPS, [installDir], 'need to make install dir') + t.match(ARB_CTOR, [{ package: packages, path }]) + t.strictSame(ARB_REIFY, [], 'no install performed') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + t.strictSame(RUN_SCRIPTS, []) + t.strictSame(READ, [{ + prompt: 'Need to install the following packages:\n bar\n foo\nOk to proceed? ', + default: 'y', + }]) + t.end() }) - t.strictSame(MKDIRPS, [installDir], 'need to make install dir') - t.match(ARB_CTOR, [{ package: packages, path }]) - t.strictSame(ARB_REIFY, [], 'no install performed') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - t.strictSame(RUN_SCRIPTS, []) - t.strictSame(READ, [{ - prompt: 'Need to install the following packages:\n bar\n foo\nOk to proceed? ', - default: 'y', - }]) }) -t.test('abort if -n provided', async t => { +t.test('abort if -n provided', t => { const stdoutTTY = process.stdout.isTTY const stdinTTY = process.stdin.isTTY t.teardown(() => { @@ -1016,18 +1043,19 @@ t.test('abort if -n provided', async t => { }, _from: 'bar@', } - await exec(['foobar'], er => { + exec.exec(['foobar'], er => { t.equal(er, 'canceled', 'should be canceled') + t.strictSame(MKDIRPS, [installDir], 'need to make install dir') + t.match(ARB_CTOR, [{ package: packages, path }]) + t.strictSame(ARB_REIFY, [], 'no install performed') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + t.strictSame(RUN_SCRIPTS, []) + t.strictSame(READ, []) + t.done() }) - t.strictSame(MKDIRPS, [installDir], 'need to make install dir') - t.match(ARB_CTOR, [{ package: packages, path }]) - t.strictSame(ARB_REIFY, [], 'no install performed') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - t.strictSame(RUN_SCRIPTS, []) - t.strictSame(READ, []) }) -t.test('forward legacyPeerDeps opt', async t => { +t.test('forward legacyPeerDeps opt', t => { const path = t.testdir() const installDir = resolve('cache-dir/_npx/f7fbba6e0636f890') npm.localPrefix = path @@ -1047,9 +1075,10 @@ t.test('forward legacyPeerDeps opt', async t => { } npm.flatOptions.yes = true npm.flatOptions.legacyPeerDeps = true - await exec(['foo'], er => { + exec.exec(['foo'], er => { if (er) throw er + t.match(ARB_REIFY, [{add: ['foo@'], legacyPeerDeps: true}], 'need to install foo@ using legacyPeerDeps opt') + t.done() }) - t.match(ARB_REIFY, [{add: ['foo@'], legacyPeerDeps: true}], 'need to install foo@ using legacyPeerDeps opt') }) diff --git a/test/lib/explain.js b/test/lib/explain.js index 1eeca8c4c..22bfb8639 100644 --- a/test/lib/explain.js +++ b/test/lib/explain.js @@ -9,9 +9,7 @@ const { resolve } = require('path') const OUTPUT = [] -const explain = requireInject('../../lib/explain.js', { - '../../lib/npm.js': npm, - +const Explain = requireInject('../../lib/explain.js', { '../../lib/utils/output.js': (...args) => { OUTPUT.push(args) }, @@ -23,44 +21,40 @@ const explain = requireInject('../../lib/explain.js', { }, }, }) +const explain = new Explain(npm) -t.test('no args throws usage', async t => { +t.test('no args throws usage', t => { t.plan(1) - try { - await explain([], er => { - throw er - }) - } catch (er) { + explain.exec([], er => { t.equal(er, explain.usage) - } + t.done() + }) }) -t.test('no match throws not found', async t => { +t.test('no match throws not found', t => { npm.prefix = t.testdir() t.plan(1) - try { - await explain(['foo@1.2.3', 'node_modules/baz'], er => { - throw er - }) - } catch (er) { + explain.exec(['foo@1.2.3', 'node_modules/baz'], er => { t.equal(er, 'No dependencies found matching foo@1.2.3, node_modules/baz') - } + }) }) -t.test('invalid package name throws not found', async t => { +t.test('invalid package name throws not found', t => { npm.prefix = t.testdir() t.plan(1) const badName = ' not a valid package name ' - try { - await explain([`${badName}@1.2.3`], er => { - throw er - }) - } catch (er) { + explain.exec([`${badName}@1.2.3`], er => { t.equal(er, `No dependencies found matching ${badName}@1.2.3`) - } + }) }) -t.test('explain some nodes', async t => { +t.test('explain some nodes', t => { + t.afterEach((cb) => { + OUTPUT.length = 0 + npm.flatOptions.json = false + cb() + }) + npm.prefix = t.testdir({ node_modules: { foo: { @@ -111,61 +105,75 @@ t.test('explain some nodes', async t => { }), }) - // works with either a full actual path or the location - const p = 'node_modules/foo' - for (const path of [p, resolve(npm.prefix, p)]) { - await explain([path], er => { + t.test('works with the location', t => { + const path = 'node_modules/foo' + explain.exec([path], er => { if (er) throw er + t.strictSame(OUTPUT, [['foo@1.2.3 depth=Infinity color=true']]) + t.end() }) - t.strictSame(OUTPUT, [['foo@1.2.3 depth=Infinity color=true']]) - OUTPUT.length = 0 - } + }) + t.test('works with a full actual path', t => { + const path = resolve(npm.prefix, 'node_modules/foo') + explain.exec([path], er => { + if (er) + throw er + t.strictSame(OUTPUT, [['foo@1.2.3 depth=Infinity color=true']]) + t.end() + }) + }) - // finds all nodes by name - await explain(['bar'], er => { - if (er) - throw er + t.test('finds all nodes by name', t => { + explain.exec(['bar'], er => { + if (er) + throw er + t.strictSame(OUTPUT, [[ + 'bar@1.2.3 depth=Infinity color=true\n\n' + + 'bar@2.3.4 depth=Infinity color=true', + ]]) + t.end() + }) }) - t.strictSame(OUTPUT, [[ - 'bar@1.2.3 depth=Infinity color=true\n\n' + - 'bar@2.3.4 depth=Infinity color=true', - ]]) - OUTPUT.length = 0 - // finds only nodes that match the spec - await explain(['bar@1'], er => { - if (er) - throw er + t.test('finds only nodes that match the spec', t => { + explain.exec(['bar@1'], er => { + if (er) + throw er + t.strictSame(OUTPUT, [['bar@1.2.3 depth=Infinity color=true']]) + t.end() + }) }) - t.strictSame(OUTPUT, [['bar@1.2.3 depth=Infinity color=true']]) - OUTPUT.length = 0 - // finds extraneous nodes - await explain(['extra'], er => { - if (er) - throw er + t.test('finds extraneous nodes', t => { + explain.exec(['extra'], er => { + if (er) + throw er + t.strictSame(OUTPUT, [['extra@99.9999.999999 depth=Infinity color=true']]) + t.end() + }) }) - t.strictSame(OUTPUT, [['extra@99.9999.999999 depth=Infinity color=true']]) - OUTPUT.length = 0 - npm.flatOptions.json = true - await explain(['node_modules/foo'], er => { - if (er) - throw er + t.test('json output', t => { + npm.flatOptions.json = true + explain.exec(['node_modules/foo'], er => { + if (er) + throw er + t.match(JSON.parse(OUTPUT[0][0]), [{ + name: 'foo', + version: '1.2.3', + dependents: Array, + }]) + t.end() + }) }) - t.match(JSON.parse(OUTPUT[0][0]), [{ - name: 'foo', - version: '1.2.3', - dependents: Array, - }]) - OUTPUT.length = 0 - npm.flatOptions.json = false - t.test('report if no nodes found', async t => { + t.test('report if no nodes found', t => { t.plan(1) - await explain(['asdf/foo/bar', 'quux@1.x'], er => { + explain.exec(['asdf/foo/bar', 'quux@1.x'], er => { t.equal(er, 'No dependencies found matching asdf/foo/bar, quux@1.x') + t.done() }) }) + t.end() }) diff --git a/test/lib/explore.js b/test/lib/explore.js index 23eab1172..6f1f3bb47 100644 --- a/test/lib/explore.js +++ b/test/lib/explore.js @@ -46,14 +46,20 @@ const mockRunScript = ({ pkg, banner, path, event, stdio }) => { const output = [] let ERROR_HANDLER_CALLED = null const logs = [] -const getExplore = windows => requireInject('../../lib/explore.js', { - '../../lib/utils/is-windows.js': windows, - path: require('path')[windows ? 'win32' : 'posix'], - '../../lib/utils/error-handler.js': er => { - ERROR_HANDLER_CALLED = er - }, - 'read-package-json-fast': mockRPJ, - '../../lib/npm.js': { +const getExplore = (windows) => { + const Explore = requireInject('../../lib/explore.js', { + '../../lib/utils/is-windows.js': windows, + path: require('path')[windows ? 'win32' : 'posix'], + '../../lib/utils/error-handler.js': er => { + ERROR_HANDLER_CALLED = er + }, + 'read-package-json-fast': mockRPJ, + '@npmcli/run-script': mockRunScript, + '../../lib/utils/output.js': out => { + output.push(out) + }, + }) + const npm = { dir: windows ? 'c:\\npm\\dir' : '/npm/dir', log: { error: (...msg) => logs.push(msg), @@ -63,12 +69,9 @@ const getExplore = windows => requireInject('../../lib/explore.js', { flatOptions: { shell: 'shell-command', }, - }, - '@npmcli/run-script': mockRunScript, - '../../lib/utils/output.js': out => { - output.push(out) - }, -}) + } + return new Explore(npm) +} const windowsExplore = getExplore(true) const posixExplore = getExplore(false) @@ -79,7 +82,7 @@ t.test('basic interactive', t => { cb() }) - t.test('windows', t => windowsExplore(['pkg'], er => { + t.test('windows', t => windowsExplore.exec(['pkg'], er => { if (er) throw er @@ -95,9 +98,10 @@ t.test('basic interactive', t => { t.strictSame(output, [ "\nExploring c:\\npm\\dir\\pkg\nType 'exit' or ^D when finished\n", ]) + t.end() })) - t.test('posix', t => posixExplore(['pkg'], er => { + t.test('posix', t => posixExplore.exec(['pkg'], er => { if (er) throw er @@ -113,6 +117,7 @@ t.test('basic interactive', t => { t.strictSame(output, [ "\nExploring /npm/dir/pkg\nType 'exit' or ^D when finished\n", ]) + t.end() })) t.end() @@ -132,7 +137,7 @@ t.test('interactive tracks exit code', t => { cb() }) - t.test('windows', t => windowsExplore(['pkg'], er => { + t.test('windows', t => windowsExplore.exec(['pkg'], er => { if (er) throw er @@ -149,9 +154,10 @@ t.test('interactive tracks exit code', t => { "\nExploring c:\\npm\\dir\\pkg\nType 'exit' or ^D when finished\n", ]) t.equal(process.exitCode, 99) + t.end() })) - t.test('posix', t => posixExplore(['pkg'], er => { + t.test('posix', t => posixExplore.exec(['pkg'], er => { if (er) throw er @@ -168,18 +174,20 @@ t.test('interactive tracks exit code', t => { "\nExploring /npm/dir/pkg\nType 'exit' or ^D when finished\n", ]) t.equal(process.exitCode, 99) + t.end() })) t.test('posix spawn fail', t => { RUN_SCRIPT_ERROR = Object.assign(new Error('glorb'), { code: 33, }) - return posixExplore(['pkg'], er => { + posixExplore.exec(['pkg'], er => { t.match(er, { message: 'glorb', code: 33 }) t.strictSame(output, [ "\nExploring /npm/dir/pkg\nType 'exit' or ^D when finished\n", ]) t.equal(process.exitCode, 33) + t.end() }) }) @@ -187,12 +195,13 @@ t.test('interactive tracks exit code', t => { RUN_SCRIPT_ERROR = Object.assign(new Error('glorb'), { code: 0, }) - return posixExplore(['pkg'], er => { + posixExplore.exec(['pkg'], er => { t.match(er, { message: 'glorb', code: 0 }) t.strictSame(output, [ "\nExploring /npm/dir/pkg\nType 'exit' or ^D when finished\n", ]) t.equal(process.exitCode, 1) + t.end() }) }) @@ -200,12 +209,13 @@ t.test('interactive tracks exit code', t => { RUN_SCRIPT_ERROR = Object.assign(new Error('command failed'), { code: 'EPROBLEM', }) - return posixExplore(['pkg'], er => { + posixExplore.exec(['pkg'], er => { t.match(er, { message: 'command failed', code: 'EPROBLEM' }) t.strictSame(output, [ "\nExploring /npm/dir/pkg\nType 'exit' or ^D when finished\n", ]) t.equal(process.exitCode, 1) + t.end() }) }) @@ -218,7 +228,7 @@ t.test('basic non-interactive', t => { cb() }) - t.test('windows', t => windowsExplore(['pkg', 'ls'], er => { + t.test('windows', t => windowsExplore.exec(['pkg', 'ls'], er => { if (er) throw er @@ -232,9 +242,10 @@ t.test('basic non-interactive', t => { RUN_SCRIPT_EXEC: 'ls', }) t.strictSame(output, []) + t.end() })) - t.test('posix', t => posixExplore(['pkg', 'ls'], er => { + t.test('posix', t => posixExplore.exec(['pkg', 'ls'], er => { if (er) throw er @@ -248,6 +259,7 @@ t.test('basic non-interactive', t => { RUN_SCRIPT_EXEC: 'ls', }) t.strictSame(output, []) + t.end() })) t.end() @@ -272,7 +284,7 @@ t.test('signal fails non-interactive', t => { cb() }) - t.test('windows', t => windowsExplore(['pkg', 'ls'], er => { + t.test('windows', t => windowsExplore.exec(['pkg', 'ls'], er => { t.match(er, { message: 'command failed', signal: 'SIGPROBLEM', @@ -286,9 +298,10 @@ t.test('signal fails non-interactive', t => { RUN_SCRIPT_EXEC: 'ls', }) t.strictSame(output, []) + t.end() })) - t.test('posix', t => posixExplore(['pkg', 'ls'], er => { + t.test('posix', t => posixExplore.exec(['pkg', 'ls'], er => { t.match(er, { message: 'command failed', signal: 'SIGPROBLEM', @@ -302,6 +315,7 @@ t.test('signal fails non-interactive', t => { RUN_SCRIPT_EXEC: 'ls', }) t.strictSame(output, []) + t.end() })) t.end() @@ -322,29 +336,28 @@ t.test('usage if no pkg provided', t => { ] t.plan(noPkg.length) for (const args of noPkg) { - t.test(JSON.stringify(args), t => posixExplore(args, er => { - t.equal(er, 'npm explore <pkg> [ -- <command>]') - t.strictSame({ - ERROR_HANDLER_CALLED: null, - RPJ_CALLED, - RUN_SCRIPT_EXEC, - }, { - ERROR_HANDLER_CALLED: null, - RPJ_CALLED: '/npm/dir/pkg/package.json', - RUN_SCRIPT_EXEC: 'ls', + t.test(JSON.stringify(args), t => { + posixExplore.exec(args, er => { + t.equal(er, 'npm explore <pkg> [ -- <command>]') + t.strictSame({ + ERROR_HANDLER_CALLED: null, + RPJ_CALLED, + RUN_SCRIPT_EXEC, + }, { + ERROR_HANDLER_CALLED: null, + RPJ_CALLED: '/npm/dir/pkg/package.json', + RUN_SCRIPT_EXEC: 'ls', + }) + t.end() }) - })) + }) } }) t.test('pkg not installed', t => { RPJ_ERROR = new Error('plurple') - t.plan(2) - - posixExplore(['pkg', 'ls'], er => { - if (er) - throw er + posixExplore.exec(['pkg', 'ls'], er => { t.strictSame({ ERROR_HANDLER_CALLED, RPJ_CALLED, @@ -355,9 +368,9 @@ t.test('pkg not installed', t => { RUN_SCRIPT_EXEC: 'ls', }) t.strictSame(output, []) - }).catch(er => { t.match(er, { message: 'plurple' }) t.match(logs, [['explore', `It doesn't look like pkg is installed.`]]) + t.end() logs.length = 0 }) }) diff --git a/test/lib/find-dupes.js b/test/lib/find-dupes.js index 73c8fa2dc..c7b33ceb6 100644 --- a/test/lib/find-dupes.js +++ b/test/lib/find-dupes.js @@ -1,15 +1,24 @@ -const { test } = require('tap') -const requireInject = require('require-inject') +const t = require('tap') -test('should run dedupe in dryRun mode', (t) => { - const findDupes = requireInject('../../lib/find-dupes.js', { - '../../lib/dedupe.js': function (args, cb) { - t.ok(args.dryRun, 'dryRun is true') - cb() +const FindDupes = require('../../lib/find-dupes.js') + +t.test('should run dedupe in dryRun mode', (t) => { + t.plan(3) + const findDupesTest = new FindDupes({ + config: { + set: (k, v) => { + t.match(k, 'dry-run') + t.match(v, true) + }, + }, + commands: { + dedupe: (args, cb) => { + t.match(args, []) + cb() + }, }, }) - findDupes(null, () => { - t.ok(true, 'callback is called') + findDupesTest.exec({}, () => { t.end() }) }) diff --git a/test/lib/fund.js b/test/lib/fund.js index 73f639b6c..831d76f15 100644 --- a/test/lib/fund.js +++ b/test/lib/fund.js @@ -188,11 +188,10 @@ const _flatOptions = { unicode: false, which: undefined, } -const openUrl = (url, msg, cb) => { - if (url === 'http://npmjs.org') { - cb(new Error('ERROR')) - return - } +const openUrl = async (npm, url, msg) => { + if (url === 'http://npmjs.org') + throw new Error('ERROR') + if (_flatOptions.json) { printUrl = JSON.stringify({ title: msg, @@ -200,16 +199,8 @@ const openUrl = (url, msg, cb) => { }) } else printUrl = `${msg}:\n ${url}` - - cb() } -const fund = requireInject('../../lib/fund.js', { - '../../lib/npm.js': { - flatOptions: _flatOptions, - get prefix () { - return _flatOptions.prefix - }, - }, +const Fund = requireInject('../../lib/fund.js', { '../../lib/utils/open-url.js': openUrl, '../../lib/utils/output.js': msg => { result += msg + '\n' @@ -222,6 +213,12 @@ const fund = requireInject('../../lib/fund.js', { : Promise.reject(new Error('ERROR')), }, }) +const fund = new Fund({ + flatOptions: _flatOptions, + get prefix () { + return _flatOptions.prefix + }, +}) test('fund with no package containing funding', t => { _flatOptions.prefix = t.testdir({ @@ -231,7 +228,7 @@ test('fund with no package containing funding', t => { }), }) - fund([], (err) => { + fund.exec([], (err) => { t.ifError(err, 'should not error out') t.matchSnapshot(result, 'should print empty funding info') result = '' @@ -242,7 +239,7 @@ test('fund with no package containing funding', t => { test('fund in which same maintainer owns all its deps', t => { _flatOptions.prefix = t.testdir(maintainerOwnsAllDeps) - fund([], (err) => { + fund.exec([], (err) => { t.ifError(err, 'should not error out') t.matchSnapshot(result, 'should print stack packages together') result = '' @@ -254,7 +251,7 @@ test('fund in which same maintainer owns all its deps, using --json option', t = _flatOptions.json = true _flatOptions.prefix = t.testdir(maintainerOwnsAllDeps) - fund([], (err) => { + fund.exec([], (err) => { t.ifError(err, 'should not error out') t.deepEqual( JSON.parse(result), @@ -292,7 +289,7 @@ test('fund in which same maintainer owns all its deps, using --json option', t = test('fund containing multi-level nested deps with no funding', t => { _flatOptions.prefix = t.testdir(nestedNoFundingPackages) - fund([], (err) => { + fund.exec([], (err) => { t.ifError(err, 'should not error out') t.matchSnapshot( result, @@ -308,7 +305,7 @@ test('fund containing multi-level nested deps with no funding, using --json opti _flatOptions.prefix = t.testdir(nestedNoFundingPackages) _flatOptions.json = true - fund([], (err) => { + fund.exec([], (err) => { t.ifError(err, 'should not error out') t.deepEqual( JSON.parse(result), @@ -340,7 +337,7 @@ test('fund containing multi-level nested deps with no funding, using --json opti _flatOptions.prefix = t.testdir(nestedMultipleFundingPackages) _flatOptions.json = true - fund([], (err) => { + fund.exec([], (err) => { t.ifError(err, 'should not error out') t.deepEqual( JSON.parse(result), @@ -397,7 +394,7 @@ test('fund does not support global', t => { _flatOptions.prefix = t.testdir({}) _flatOptions.global = true - fund([], (err) => { + fund.exec([], (err) => { t.match(err.code, 'EFUNDGLOBAL', 'should throw EFUNDGLOBAL error') result = '' @@ -409,7 +406,7 @@ test('fund does not support global', t => { test('fund using package argument', t => { _flatOptions.prefix = t.testdir(maintainerOwnsAllDeps) - fund(['.'], (err) => { + fund.exec(['.'], (err) => { t.ifError(err, 'should not error out') t.matchSnapshot(printUrl, 'should open funding url') @@ -423,7 +420,7 @@ test('fund does not support global, using --json option', t => { _flatOptions.global = true _flatOptions.json = true - fund([], (err) => { + fund.exec([], (err) => { t.equal(err.code, 'EFUNDGLOBAL', 'should use EFUNDGLOBAL error code') t.equal( err.message, @@ -446,7 +443,7 @@ test('fund using string shorthand', t => { }), }) - fund(['.'], (err) => { + fund.exec(['.'], (err) => { t.ifError(err, 'should not error out') t.matchSnapshot(printUrl, 'should open string-only url') @@ -458,7 +455,7 @@ test('fund using string shorthand', t => { test('fund using nested packages with multiple sources', t => { _flatOptions.prefix = t.testdir(nestedMultipleFundingPackages) - fund(['.'], (err) => { + fund.exec(['.'], (err) => { t.ifError(err, 'should not error out') t.matchSnapshot(result, 'should prompt with all available URLs') @@ -486,7 +483,7 @@ test('fund using symlink ref', t => { }) // using symlinked ref - fund(['./node_modules/a'], (err) => { + fund.exec(['./node_modules/a'], (err) => { t.ifError(err, 'should not error out') t.match( printUrl, @@ -497,7 +494,7 @@ test('fund using symlink ref', t => { printUrl = '' // using target ref - fund(['./a'], (err) => { + fund.exec(['./a'], (err) => { t.ifError(err, 'should not error out') t.match( @@ -547,7 +544,7 @@ test('fund using data from actual tree', t => { }) // using symlinked ref - fund(['a'], (err) => { + fund.exec(['a'], (err) => { t.ifError(err, 'should not error out') t.match( printUrl, @@ -564,7 +561,7 @@ test('fund using nested packages with multiple sources, with a source number', t _flatOptions.prefix = t.testdir(nestedMultipleFundingPackages) _flatOptions.which = '1' - fund(['.'], (err) => { + fund.exec(['.'], (err) => { t.ifError(err, 'should not error out') t.matchSnapshot(printUrl, 'should open the numbered URL') @@ -578,7 +575,7 @@ test('fund using pkg name while having conflicting versions', t => { _flatOptions.prefix = t.testdir(conflictingFundingPackages) _flatOptions.which = '1' - fund(['foo'], (err) => { + fund.exec(['foo'], (err) => { t.ifError(err, 'should not error out') t.matchSnapshot(printUrl, 'should open greatest version') @@ -591,7 +588,7 @@ test('fund using package argument with no browser, using --json option', t => { _flatOptions.prefix = t.testdir(maintainerOwnsAllDeps) _flatOptions.json = true - fund(['.'], (err) => { + fund.exec(['.'], (err) => { t.ifError(err, 'should not error out') t.deepEqual( JSON.parse(printUrl), @@ -611,7 +608,7 @@ test('fund using package argument with no browser, using --json option', t => { test('fund using package info fetch from registry', t => { _flatOptions.prefix = t.testdir({}) - fund(['ntl'], (err) => { + fund.exec(['ntl'], (err) => { t.ifError(err, 'should not error out') t.match( printUrl, @@ -627,7 +624,7 @@ test('fund using package info fetch from registry', t => { test('fund tries to use package info fetch from registry but registry has nothing', t => { _flatOptions.prefix = t.testdir({}) - fund(['foo'], (err) => { + fund.exec(['foo'], (err) => { t.equal(err.code, 'ENOFUND', 'should have ENOFUND error code') t.equal( err.message, @@ -643,7 +640,7 @@ test('fund tries to use package info fetch from registry but registry has nothin test('fund but target module has no funding info', t => { _flatOptions.prefix = t.testdir(nestedNoFundingPackages) - fund(['foo'], (err) => { + fund.exec(['foo'], (err) => { t.equal(err.code, 'ENOFUND', 'should have ENOFUND error code') t.equal( err.message, @@ -660,7 +657,7 @@ test('fund using bad which value', t => { _flatOptions.prefix = t.testdir(nestedMultipleFundingPackages) _flatOptions.which = 3 - fund(['bar'], (err) => { + fund.exec(['bar'], (err) => { t.equal(err.code, 'EFUNDNUMBER', 'should have EFUNDNUMBER error code') t.equal( err.message, @@ -682,7 +679,7 @@ test('fund pkg missing version number', t => { }), }) - fund([], (err) => { + fund.exec([], (err) => { t.ifError(err, 'should not error out') t.matchSnapshot(result, 'should print name only') result = '' @@ -699,7 +696,7 @@ test('fund a package throws on openUrl', t => { }), }) - fund(['.'], (err) => { + fund.exec(['.'], (err) => { t.equal(err.message, 'ERROR', 'should throw unknown error') result = '' t.end() @@ -723,7 +720,7 @@ test('fund a package with type and multiple sources', t => { }), }) - fund(['.'], (err) => { + fund.exec(['.'], (err) => { t.ifError(err, 'should not error out') t.matchSnapshot(result, 'should print prompt select message') @@ -787,7 +784,7 @@ test('fund colors', t => { }) _flatOptions.color = true - fund([], (err) => { + fund.exec([], (err) => { t.ifError(err, 'should not error out') t.matchSnapshot(result, 'should print output with color info') @@ -837,7 +834,7 @@ test('sub dep with fund info and a parent with no funding info', t => { }, }) - fund([], (err) => { + fund.exec([], (err) => { t.ifError(err, 'should not error out') t.matchSnapshot(result, 'should nest sub dep as child of root') diff --git a/test/lib/get.js b/test/lib/get.js index 5260c00ba..a11597d26 100644 --- a/test/lib/get.js +++ b/test/lib/get.js @@ -2,17 +2,16 @@ const { test } = require('tap') const requireInject = require('require-inject') test('should retrieve values from npm.commands.config', (t) => { - const get = requireInject('../../lib/get.js', { - '../../lib/npm.js': { - commands: { - config: ([action, arg]) => { - t.equal(action, 'get', 'should use config get action') - t.equal(arg, 'foo', 'should use expected key') - t.end() - }, + const Get = requireInject('../../lib/get.js') + const get = new Get({ + commands: { + config: ([action, arg]) => { + t.equal(action, 'get', 'should use config get action') + t.equal(arg, 'foo', 'should use expected key') + t.end() }, }, }) - get(['foo']) + get.exec(['foo']) }) diff --git a/test/lib/help-search.js b/test/lib/help-search.js index f74e2f1ef..8b1ecd46e 100644 --- a/test/lib/help-search.js +++ b/test/lib/help-search.js @@ -24,7 +24,7 @@ const npm = { } let npmUsageArg = null -const npmUsage = (arg) => { +const npmUsage = (npm, arg) => { npmUsageArg = arg } @@ -43,12 +43,12 @@ const globDir = { const glob = (p, cb) => cb(null, Object.keys(globDir).map((file) => join(globRoot, file))) -const helpSearch = requireInject('../../lib/help-search.js', { - '../../lib/npm.js': npm, +const HelpSearch = requireInject('../../lib/help-search.js', { '../../lib/utils/npm-usage.js': npmUsage, '../../lib/utils/output.js': output, glob, }) +const helpSearch = new HelpSearch(npm) test('npm help-search', t => { globRoot = t.testdir(globDir) @@ -57,7 +57,7 @@ test('npm help-search', t => { globRoot = null }) - return helpSearch(['exec'], (err) => { + return helpSearch.exec(['exec'], (err) => { if (err) throw err @@ -74,7 +74,7 @@ test('npm help-search multiple terms', t => { globRoot = null }) - return helpSearch(['run', 'script'], (err) => { + return helpSearch.exec(['run', 'script'], (err) => { if (err) throw err @@ -92,7 +92,7 @@ test('npm help-search single result prints full section', t => { globRoot = null }) - return helpSearch(['does not exist in'], (err) => { + return helpSearch.exec(['does not exist in'], (err) => { if (err) throw err @@ -111,7 +111,7 @@ test('npm help-search single result propagates error', t => { globRoot = null }) - return helpSearch(['does not exist in'], (err) => { + return helpSearch.exec(['does not exist in'], (err) => { t.strictSame(npmHelpArgs, ['npm-install'], 'identified the correct man page and called help with it') t.match(err, /help broke/, 'propagated the error from help') t.end() @@ -127,7 +127,7 @@ test('npm help-search long output', t => { globRoot = null }) - return helpSearch(['exec'], (err) => { + return helpSearch.exec(['exec'], (err) => { if (err) throw err @@ -147,7 +147,7 @@ test('npm help-search long output with color', t => { globRoot = null }) - return helpSearch(['help-search'], (err) => { + return helpSearch.exec(['help-search'], (err) => { if (err) throw err @@ -158,7 +158,7 @@ test('npm help-search long output with color', t => { }) test('npm help-search no args', t => { - return helpSearch([], (err) => { + return helpSearch.exec([], (err) => { t.match(err, /npm help-search/, 'throws usage') t.end() }) @@ -172,7 +172,7 @@ test('npm help-search no matches', t => { globRoot = null }) - return helpSearch(['asdfasdf'], (err) => { + return helpSearch.exec(['asdfasdf'], (err) => { if (err) throw err diff --git a/test/lib/help.js b/test/lib/help.js index fc4a32e07..addbe4dcc 100644 --- a/test/lib/help.js +++ b/test/lib/help.js @@ -3,7 +3,7 @@ const requireInject = require('require-inject') const { EventEmitter } = require('events') let npmUsageArg = null -const npmUsage = (arg) => { +const npmUsage = (npm, arg) => { npmUsageArg = arg } @@ -67,13 +67,11 @@ const spawn = (bin, args) => { } let openUrlArg = null -const openUrl = (url, msg, cb) => { +const openUrl = async (npm, url, msg) => { openUrlArg = url - return cb() } -const help = requireInject('../../lib/help.js', { - '../../lib/npm.js': npm, +const Help = requireInject('../../lib/help.js', { '../../lib/utils/npm-usage.js': npmUsage, '../../lib/utils/open-url.js': openUrl, '../../lib/utils/output.js': output, @@ -82,13 +80,14 @@ const help = requireInject('../../lib/help.js', { }, glob, }) +const help = new Help(npm) test('npm help', t => { t.teardown(() => { npmUsageArg = null }) - return help([], (err) => { + return help.exec([], (err) => { if (err) throw err @@ -117,7 +116,7 @@ test('npm help -h', t => { OUTPUT.length = 0 }) - return help(['help'], (err) => { + return help.exec(['help'], (err) => { if (err) throw err @@ -131,7 +130,7 @@ test('npm help multiple args calls search', t => { helpSearchArgs = null }) - return help(['run', 'script'], (err) => { + return help.exec(['run', 'script'], (err) => { if (err) throw err @@ -147,7 +146,7 @@ test('npm help no matches calls search', t => { globResult = globDefaults }) - return help(['asdfasdf'], (err) => { + return help.exec(['asdfasdf'], (err) => { if (err) throw err @@ -164,7 +163,7 @@ test('npm help glob errors propagate', t => { spawnArgs = null }) - return help(['whoami'], (err) => { + return help.exec(['whoami'], (err) => { t.match(err, /glob failed/, 'glob error propagates') t.end() }) @@ -178,7 +177,7 @@ test('npm help whoami', t => { spawnArgs = null }) - return help(['whoami'], (err) => { + return help.exec(['whoami'], (err) => { if (err) throw err @@ -202,7 +201,7 @@ test('npm help 1 install', t => { spawnArgs = null }) - return help(['1', 'install'], (err) => { + return help.exec(['1', 'install'], (err) => { if (err) throw err @@ -225,7 +224,7 @@ test('npm help 5 install', t => { spawnArgs = null }) - return help(['5', 'install'], (err) => { + return help.exec(['5', 'install'], (err) => { if (err) throw err @@ -247,7 +246,7 @@ test('npm help 7 config', t => { spawnArgs = null }) - return help(['7', 'config'], (err) => { + return help.exec(['7', 'config'], (err) => { if (err) throw err @@ -270,7 +269,7 @@ test('npm help with browser viewer and invalid section throws', t => { spawnArgs = null }) - return help(['9', 'config'], (err) => { + return help.exec(['9', 'config'], (err) => { t.match(err, /invalid man section: 9/, 'throws appropriate error') t.end() }) @@ -284,7 +283,7 @@ test('npm help global redirects to folders', t => { spawnArgs = null }) - return help(['global'], (err) => { + return help.exec(['global'], (err) => { if (err) throw err @@ -302,7 +301,7 @@ test('npm help package.json redirects to package-json', t => { spawnArgs = null }) - return help(['package.json'], (err) => { + return help.exec(['package.json'], (err) => { if (err) throw err @@ -325,7 +324,7 @@ test('npm help ?(un)star', t => { spawnArgs = null }) - return help(['?(un)star'], (err) => { + return help.exec(['?(un)star'], (err) => { if (err) throw err @@ -350,7 +349,7 @@ test('npm help - woman viewer propagates errors', t => { spawnArgs = null }) - return help(['?(un)star'], (err) => { + return help.exec(['?(un)star'], (err) => { t.match(err, /help process exited with code: 1/, 'received the correct error') t.equal(spawnBin, 'emacsclient', 'maps woman to emacs correctly') t.strictSame(spawnArgs, ['-e', `(woman-find-file '/root/man/man1/npm-unstar.1')`], 'passes the correct arguments') @@ -370,7 +369,7 @@ test('npm help un*', t => { spawnArgs = null }) - return help(['un*'], (err) => { + return help.exec(['un*'], (err) => { if (err) throw err @@ -394,7 +393,7 @@ test('npm help - man viewer propagates errors', t => { spawnArgs = null }) - return help(['un*'], (err) => { + return help.exec(['un*'], (err) => { t.match(err, /help process exited with code: 1/, 'received correct error') t.equal(spawnBin, 'man', 'calls man by default') t.strictSame(spawnArgs, ['1', 'npm-unstar'], 'passes the correct arguments') diff --git a/test/lib/hook.js b/test/lib/hook.js index 359904202..923f86e81 100644 --- a/test/lib/hook.js +++ b/test/lib/hook.js @@ -52,17 +52,17 @@ const libnpmhook = { } const output = [] -const hook = requireInject('../../lib/hook.js', { - '../../lib/npm.js': npm, +const Hook = requireInject('../../lib/hook.js', { '../../lib/utils/otplease.js': async (opts, fn) => fn(opts), '../../lib/utils/output.js': (msg) => { output.push(msg) }, libnpmhook, }) +const hook = new Hook(npm) test('npm hook no args', t => { - return hook([], (err) => { + return hook.exec([], (err) => { t.match(err, /npm hook add/, 'throws usage with no arguments') t.end() }) @@ -74,7 +74,7 @@ test('npm hook add', t => { output.length = 0 }) - return hook(['add', 'semver', 'https://google.com', 'some-secret'], (err) => { + return hook.exec(['add', 'semver', 'https://google.com', 'some-secret'], (err) => { if (err) throw err @@ -97,7 +97,7 @@ test('npm hook add - unicode output', t => { output.length = 0 }) - return hook(['add', 'semver', 'https://google.com', 'some-secret'], (err) => { + return hook.exec(['add', 'semver', 'https://google.com', 'some-secret'], (err) => { if (err) throw err @@ -120,7 +120,7 @@ test('npm hook add - json output', t => { output.length = 0 }) - return hook(['add', '@npmcli', 'https://google.com', 'some-secret'], (err) => { + return hook.exec(['add', '@npmcli', 'https://google.com', 'some-secret'], (err) => { if (err) throw err @@ -148,7 +148,7 @@ test('npm hook add - parseable output', t => { output.length = 0 }) - return hook(['add', '@npmcli', 'https://google.com', 'some-secret'], (err) => { + return hook.exec(['add', '@npmcli', 'https://google.com', 'some-secret'], (err) => { if (err) throw err @@ -176,7 +176,7 @@ test('npm hook add - silent output', t => { output.length = 0 }) - return hook(['add', '@npmcli', 'https://google.com', 'some-secret'], (err) => { + return hook.exec(['add', '@npmcli', 'https://google.com', 'some-secret'], (err) => { if (err) throw err @@ -197,7 +197,7 @@ test('npm hook ls', t => { output.length = 0 }) - return hook(['ls'], (err) => { + return hook.exec(['ls'], (err) => { if (err) throw err @@ -222,7 +222,7 @@ test('npm hook ls, no results', t => { output.length = 0 }) - return hook(['ls'], (err) => { + return hook.exec(['ls'], (err) => { if (err) throw err @@ -249,7 +249,7 @@ test('npm hook ls, single result', t => { output.length = 0 }) - return hook(['ls'], (err) => { + return hook.exec(['ls'], (err) => { if (err) throw err @@ -272,7 +272,7 @@ test('npm hook ls - json output', t => { output.length = 0 }) - return hook(['ls'], (err) => { + return hook.exec(['ls'], (err) => { if (err) throw err @@ -309,7 +309,7 @@ test('npm hook ls - parseable output', t => { output.length = 0 }) - return hook(['ls'], (err) => { + return hook.exec(['ls'], (err) => { if (err) throw err @@ -335,7 +335,7 @@ test('npm hook ls - silent output', t => { output.length = 0 }) - return hook(['ls'], (err) => { + return hook.exec(['ls'], (err) => { if (err) throw err @@ -354,7 +354,7 @@ test('npm hook rm', t => { output.length = 0 }) - return hook(['rm', '1'], (err) => { + return hook.exec(['rm', '1'], (err) => { if (err) throw err @@ -377,7 +377,7 @@ test('npm hook rm - unicode output', t => { output.length = 0 }) - return hook(['rm', '1'], (err) => { + return hook.exec(['rm', '1'], (err) => { if (err) throw err @@ -400,7 +400,7 @@ test('npm hook rm - silent output', t => { output.length = 0 }) - return hook(['rm', '1'], (err) => { + return hook.exec(['rm', '1'], (err) => { if (err) throw err @@ -421,7 +421,7 @@ test('npm hook rm - json output', t => { output.length = 0 }) - return hook(['rm', '1'], (err) => { + return hook.exec(['rm', '1'], (err) => { if (err) throw err @@ -447,7 +447,7 @@ test('npm hook rm - parseable output', t => { output.length = 0 }) - return hook(['rm', '1'], (err) => { + return hook.exec(['rm', '1'], (err) => { if (err) throw err @@ -469,7 +469,7 @@ test('npm hook update', t => { output.length = 0 }) - return hook(['update', '1', 'https://google.com', 'some-secret'], (err) => { + return hook.exec(['update', '1', 'https://google.com', 'some-secret'], (err) => { if (err) throw err @@ -494,7 +494,7 @@ test('npm hook update - unicode', t => { output.length = 0 }) - return hook(['update', '1', 'https://google.com', 'some-secret'], (err) => { + return hook.exec(['update', '1', 'https://google.com', 'some-secret'], (err) => { if (err) throw err @@ -519,7 +519,7 @@ test('npm hook update - json output', t => { output.length = 0 }) - return hook(['update', '1', 'https://google.com', 'some-secret'], (err) => { + return hook.exec(['update', '1', 'https://google.com', 'some-secret'], (err) => { if (err) throw err @@ -547,7 +547,7 @@ test('npm hook update - parseable output', t => { output.length = 0 }) - return hook(['update', '1', 'https://google.com', 'some-secret'], (err) => { + return hook.exec(['update', '1', 'https://google.com', 'some-secret'], (err) => { if (err) throw err @@ -573,7 +573,7 @@ test('npm hook update - silent output', t => { output.length = 0 }) - return hook(['update', '1', 'https://google.com', 'some-secret'], (err) => { + return hook.exec(['update', '1', 'https://google.com', 'some-secret'], (err) => { if (err) throw err diff --git a/test/lib/init.js b/test/lib/init.js index e73cc4b30..db5411ba7 100644 --- a/test/lib/init.js +++ b/test/lib/init.js @@ -17,13 +17,13 @@ const npm = { } const mocks = { 'init-package-json': (dir, initFile, config, cb) => cb(null, 'data'), - '../../lib/npm.js': npm, '../../lib/utils/usage.js': () => 'usage instructions', '../../lib/utils/output.js': (...msg) => { result += msg.join('\n') }, } -const init = requireInject('../../lib/init.js', mocks) +const Init = requireInject('../../lib/init.js', mocks) +const init = new Init(npm) t.afterEach(cb => { result = '' @@ -40,7 +40,7 @@ t.test('classic npm init no args', t => { return '~/.npm-init.js' }, } - init([], err => { + init.exec([], err => { t.ifError(err, 'npm init no args') t.matchSnapshot(result, 'should print helper info') t.end() @@ -65,7 +65,7 @@ t.test('classic npm init -y', t => { t.equal(title, 'init', 'should print title') t.equal(msg, 'written successfully', 'should print done info') } - init([], err => { + init.exec([], err => { t.ifError(err, 'npm init -y') t.equal(result, '') }) @@ -87,7 +87,7 @@ t.test('npm init <arg>', t => { ) cb() } - init(['react-app'], err => { + init.exec(['react-app'], err => { t.ifError(err, 'npm init react-app') }) }) @@ -102,7 +102,7 @@ t.test('npm init @scope/name', t => { ) cb() } - init(['@npmcli/something'], err => { + init.exec(['@npmcli/something'], err => { t.ifError(err, 'npm init init @scope/name') }) }) @@ -117,7 +117,7 @@ t.test('npm init git spec', t => { ) cb() } - init(['npm/something'], err => { + init.exec(['npm/something'], err => { t.ifError(err, 'npm init init @scope/name') }) }) @@ -132,13 +132,13 @@ t.test('npm init @scope', t => { ) cb() } - init(['@npmcli'], err => { + init.exec(['@npmcli'], err => { t.ifError(err, 'npm init init @scope/create') }) }) t.test('npm init tgz', t => { - init(['something.tgz'], err => { + init.exec(['something.tgz'], err => { t.match( err, /Error: Unrecognized initializer: something.tgz/, @@ -158,7 +158,7 @@ t.test('npm init <arg>@next', t => { ) cb() } - init(['something@next'], err => { + init.exec(['something@next'], err => { t.ifError(err, 'npm init init something@next') }) }) @@ -167,7 +167,7 @@ t.test('npm init exec error', t => { npm.commands.exec = (arr, cb) => { cb(new Error('ERROR')) } - init(['something@next'], err => { + init.exec(['something@next'], err => { t.match( err, /ERROR/, @@ -199,37 +199,39 @@ t.test('should not rewrite flatOptions', t => { ) cb() } - init(['react-app', 'my-app'], err => { + init.exec(['react-app', 'my-app'], err => { t.ifError(err, 'npm init react-app') }) }) t.test('npm init cancel', t => { t.plan(3) - const init = requireInject('../../lib/init.js', { + const Init = requireInject('../../lib/init.js', { ...mocks, 'init-package-json': (dir, initFile, config, cb) => cb( new Error('canceled') ), }) + const init = new Init(npm) npm.log = { ...npm.log } npm.log.warn = (title, msg) => { t.equal(title, 'init', 'should have init title') t.equal(msg, 'canceled', 'should log canceled') } - init([], err => { + init.exec([], err => { t.ifError(err, 'npm init cancel') }) }) t.test('npm init error', t => { - const init = requireInject('../../lib/init.js', { + const Init = requireInject('../../lib/init.js', { ...mocks, 'init-package-json': (dir, initFile, config, cb) => cb( new Error('Unknown Error') ), }) - init([], err => { + const init = new Init(npm) + init.exec([], err => { t.match(err, /Unknown Error/, 'should throw error') t.end() }) diff --git a/test/lib/install-ci-test.js b/test/lib/install-ci-test.js new file mode 100644 index 000000000..5f30efcab --- /dev/null +++ b/test/lib/install-ci-test.js @@ -0,0 +1,57 @@ +const t = require('tap') + +const InstallCITest = require('../../lib/install-ci-test.js') + +let ciArgs = null +let ciCalled = false +let testArgs = null +let testCalled = false +let ciError = null + +const installCITest = new InstallCITest({ + commands: { + ci: (args, cb) => { + ciArgs = args + ciCalled = true + cb(ciError) + }, + test: (args, cb) => { + testArgs = args + testCalled = true + cb() + }, + }, +}) + +t.test('the install-ci-test command', t => { + t.afterEach(cb => { + ciArgs = null + ciCalled = false + testArgs = null + testCalled = false + ciError = null + cb() + }) + + t.test('ci and test', t => { + installCITest.exec(['extra'], () => { + t.equal(ciCalled, true) + t.equal(testCalled, true) + t.match(ciArgs, ['extra']) + t.match(testArgs, []) + t.end() + }) + }) + + t.test('ci fails', t => { + ciError = new Error('test fail') + installCITest.exec(['extra'], (err) => { + t.equal(ciCalled, true) + t.equal(testCalled, false) + t.match(ciArgs, ['extra']) + t.match(err, { message: 'test fail' }) + t.end() + }) + }) + t.end() +}) diff --git a/test/lib/install-test.js b/test/lib/install-test.js new file mode 100644 index 000000000..0c52bd5e3 --- /dev/null +++ b/test/lib/install-test.js @@ -0,0 +1,57 @@ +const t = require('tap') + +const InstallTest = require('../../lib/install-test.js') + +let installArgs = null +let installCalled = false +let testArgs = null +let testCalled = false +let installError = null + +const installTest = new InstallTest({ + commands: { + install: (args, cb) => { + installArgs = args + installCalled = true + cb(installError) + }, + test: (args, cb) => { + testArgs = args + testCalled = true + cb() + }, + }, +}) + +t.test('the install-test command', t => { + t.afterEach(cb => { + installArgs = null + installCalled = false + testArgs = null + testCalled = false + installError = null + cb() + }) + + t.test('install and test', t => { + installTest.exec(['extra'], () => { + t.equal(installCalled, true) + t.equal(testCalled, true) + t.match(installArgs, ['extra']) + t.match(testArgs, []) + t.end() + }) + }) + + t.test('install fails', t => { + installError = new Error('test fail') + installTest.exec(['extra'], (err) => { + t.equal(installCalled, true) + t.equal(testCalled, false) + t.match(installArgs, ['extra']) + t.match(err, { message: 'test fail' }) + t.end() + }) + }) + t.end() +}) diff --git a/test/lib/install.js b/test/lib/install.js index 859a4bdaa..8b7a96851 100644 --- a/test/lib/install.js +++ b/test/lib/install.js @@ -1,6 +1,6 @@ const { test } = require('tap') -const install = require('../../lib/install.js') +const Install = require('../../lib/install.js') const requireInject = require('require-inject') test('should install using Arborist', (t) => { @@ -9,17 +9,7 @@ test('should install using Arborist', (t) => { let REIFY_CALLED = false let ARB_OBJ = null - const install = requireInject('../../lib/install.js', { - '../../lib/npm.js': { - globalDir: 'path/to/node_modules/', - prefix: 'foo', - flatOptions: { - global: false, - }, - config: { - get: () => true, - }, - }, + const Install = requireInject('../../lib/install.js', { '@npmcli/run-script': ({ event }) => { SCRIPTS.push(event) }, @@ -33,14 +23,24 @@ test('should install using Arborist', (t) => { REIFY_CALLED = true } }, - '../../lib/utils/reify-finish.js': arb => { + '../../lib/utils/reify-finish.js': (npm, arb) => { if (arb !== ARB_OBJ) throw new Error('got wrong object passed to reify-finish') }, }) + const install = new Install({ + globalDir: 'path/to/node_modules/', + prefix: 'foo', + flatOptions: { + global: false, + }, + config: { + get: () => true, + }, + }) t.test('with args', t => { - install(['fizzbuzz'], er => { + install.exec(['fizzbuzz'], er => { if (er) throw er t.match(ARB_ARGS, { global: false, path: 'foo' }) @@ -51,7 +51,7 @@ test('should install using Arborist', (t) => { }) t.test('just a local npm install', t => { - install([], er => { + install.exec([], er => { if (er) throw er t.match(ARB_ARGS, { global: false, path: 'foo' }) @@ -75,19 +75,8 @@ test('should install using Arborist', (t) => { test('should ignore scripts with --ignore-scripts', (t) => { const SCRIPTS = [] let REIFY_CALLED = false - const install = requireInject('../../lib/install.js', { + const Install = requireInject('../../lib/install.js', { '../../lib/utils/reify-finish.js': async () => {}, - '../../lib/npm.js': { - globalDir: 'path/to/node_modules/', - prefix: 'foo', - flatOptions: { - global: false, - ignoreScripts: true, - }, - config: { - get: () => false, - }, - }, '@npmcli/run-script': ({ event }) => { SCRIPTS.push(event) }, @@ -97,7 +86,18 @@ test('should ignore scripts with --ignore-scripts', (t) => { } }, }) - install([], er => { + const install = new Install({ + globalDir: 'path/to/node_modules/', + prefix: 'foo', + flatOptions: { + global: false, + ignoreScripts: true, + }, + config: { + get: () => false, + }, + }) + install.exec([], er => { if (er) throw er t.equal(REIFY_CALLED, true, 'called reify') @@ -107,23 +107,23 @@ test('should ignore scripts with --ignore-scripts', (t) => { }) test('should install globally using Arborist', (t) => { - const install = requireInject('../../lib/install.js', { + const Install = requireInject('../../lib/install.js', { '../../lib/utils/reify-finish.js': async () => {}, - '../../lib/npm.js': { - globalDir: 'path/to/node_modules/', - prefix: 'foo', - flatOptions: { - global: true, - }, - config: { - get: () => false, - }, - }, '@npmcli/arborist': function () { this.reify = () => {} }, }) - install([], er => { + const install = new Install({ + globalDir: 'path/to/node_modules/', + prefix: 'foo', + flatOptions: { + global: true, + }, + config: { + get: () => false, + }, + }) + install.exec([], er => { if (er) throw er t.end() @@ -131,7 +131,7 @@ test('should install globally using Arborist', (t) => { }) test('completion to folder', async t => { - const install = requireInject('../../lib/install.js', { + const Install = requireInject('../../lib/install.js', { '../../lib/utils/reify-finish.js': async () => {}, util: { promisify: (fn) => fn, @@ -145,6 +145,7 @@ test('completion to folder', async t => { }, }, }) + const install = new Install({}) const res = await install.completion({ partialWord: '/ar' }) const expect = process.platform === 'win32' ? '\\arborist' : '/arborist' t.strictSame(res, [expect], 'package dir match') @@ -152,7 +153,7 @@ test('completion to folder', async t => { }) test('completion to folder - invalid dir', async t => { - const install = requireInject('../../lib/install.js', { + const Install = requireInject('../../lib/install.js', { '../../lib/utils/reify-finish.js': async () => {}, util: { promisify: (fn) => fn, @@ -163,13 +164,14 @@ test('completion to folder - invalid dir', async t => { }, }, }) + const install = new Install({}) const res = await install.completion({ partialWord: 'path/to/folder' }) t.strictSame(res, [], 'invalid dir: no matching') t.end() }) test('completion to folder - no matches', async t => { - const install = requireInject('../../lib/install.js', { + const Install = requireInject('../../lib/install.js', { '../../lib/utils/reify-finish.js': async () => {}, util: { promisify: (fn) => fn, @@ -180,13 +182,14 @@ test('completion to folder - no matches', async t => { }, }, }) + const install = new Install({}) const res = await install.completion({ partialWord: '/pa' }) t.strictSame(res, [], 'no name match') t.end() }) test('completion to folder - match is not a package', async t => { - const install = requireInject('../../lib/install.js', { + const Install = requireInject('../../lib/install.js', { '../../lib/utils/reify-finish.js': async () => {}, util: { promisify: (fn) => fn, @@ -200,18 +203,21 @@ test('completion to folder - match is not a package', async t => { }, }, }) + const install = new Install({}) const res = await install.completion({ partialWord: '/ar' }) t.strictSame(res, [], 'no name match') t.end() }) test('completion to url', async t => { + const install = new Install({}) const res = await install.completion({ partialWord: 'http://path/to/url' }) t.strictSame(res, []) t.end() }) test('completion', async t => { + const install = new Install({}) const res = await install.completion({ partialWord: 'toto' }) t.notOk(res) t.end() diff --git a/test/lib/link.js b/test/lib/link.js index b1048427d..be7af3f52 100644 --- a/test/lib/link.js +++ b/test/lib/link.js @@ -40,11 +40,11 @@ const printLinks = async (opts) => { } const mocks = { - '../../lib/npm.js': npm, '../../lib/utils/reify-output.js': () => reifyOutput(), } -const link = requireInject('../../lib/link.js', mocks) +const Link = requireInject('../../lib/link.js', mocks) +const link = new Link(npm) t.test('link to globalDir when in current working dir of pkg and no args', (t) => { t.plan(2) @@ -83,7 +83,7 @@ t.test('link to globalDir when in current working dir of pkg and no args', (t) = t.matchSnapshot(links, 'should create a global link to current pkg') } - link([], (err) => { + link.exec([], (err) => { t.ifError(err, 'should not error out') }) }) @@ -185,7 +185,7 @@ t.test('link global linked pkg to local nm when using args', (t) => { // - @myscope/bar: prev installed scoped package available in globalDir // - a: prev installed package available in globalDir // - file:./link-me-too: pkg that needs to be reified in globalDir first - link([ + link.exec([ 'test-pkg-link', '@myscope/linked', '@myscope/bar', @@ -254,7 +254,7 @@ t.test('link pkg already in global space', (t) => { // - @myscope/bar: prev installed scoped package available in globalDir // - a: prev installed package available in globalDir // - file:./link-me-too: pkg that needs to be reified in globalDir first - link(['@myscope/linked'], (err) => { + link.exec(['@myscope/linked'], (err) => { t.ifError(err, 'should not error out') }) }) @@ -312,7 +312,7 @@ t.test('link pkg already in global space when prefix is a symlink', (t) => { t.matchSnapshot(links, 'should create a local symlink to global pkg') } - link(['@myscope/linked'], (err) => { + link.exec(['@myscope/linked'], (err) => { t.ifError(err, 'should not error out') }) }) @@ -341,21 +341,18 @@ t.test('completion', async t => { t.end() }) -t.test('--global option', async t => { +t.test('--global option', t => { const _config = npm.config npm.config = { get () { return true } } - try { - await link([]) - t.fail('should not get here') - } catch (err) { + link.exec([], (err) => { npm.config = _config t.match( err.message, /link should never be --global/, 'should throw an useful error' ) - } - t.end() + t.end() + }) }) diff --git a/test/lib/ll.js b/test/lib/ll.js index 7d4e2b94f..45eb4ec95 100644 --- a/test/lib/ll.js +++ b/test/lib/ll.js @@ -1,31 +1,34 @@ -const t = require('tap') const requireInject = require('require-inject') -const configs = {} -let lsCalled = false -const ll = requireInject('../../lib/ll.js', { - '../../lib/npm.js': { +const t = require('tap') + +t.test('ll', t => { + t.plan(3) + + class LS { + constructor (npm) { + this.npm = npm + } + + exec (args, cb) { + t.deepEqual(args, ['pkg'], 'should forward args') + cb() + } + } + + const LL = requireInject('../../lib/ll.js', { + '../../lib/ls.js': LS, + }) + const ll = new LL({ config: { - set: (k, v) => { - configs[k] = v - }, - }, - commands: { - ls: (args, cb) => { - lsCalled = true - cb() + set: (key, value) => { + t.equal(key, 'long', 'should set long config value') + t.equal(value, true, 'should set a truthy value') }, }, - }, -}) + }) -const ls = require('../../lib/ls.js') -const { usage, completion } = ls -t.equal(ll.usage, usage) -t.equal(ll.completion.toString(), completion.toString()) -t.test('the ll command', t => { - ll([], () => { - t.equal(lsCalled, true) - t.strictSame(configs, { long: true }) - t.end() + ll.exec(['pkg'], err => { + if (err) + throw err }) }) diff --git a/test/lib/load-all-commands.js b/test/lib/load-all-commands.js index 02cb0be65..f6d1ae9e1 100644 --- a/test/lib/load-all-commands.js +++ b/test/lib/load-all-commands.js @@ -1,4 +1,6 @@ -// just for gathering coverage info +// Thanks to nyc not working properly with proxies this +// doesn't affect coverage. but it does ensure that every command +// has a usage, and if it has completion it is a function const npm = require('../../lib/npm.js') const t = require('tap') const { cmdList } = require('../../lib/utils/cmd-list.js') @@ -19,7 +21,7 @@ t.test('load each command', t => { } else t.plan(2) t.isa(impl, 'function', 'implementation is a function') - t.isa(impl.usage, 'string', 'usage is a string') + t.match(impl.usage, cmd, 'usage contains the command') }) } }) diff --git a/test/lib/logout.js b/test/lib/logout.js index 96b1bcc7f..b00fa641d 100644 --- a/test/lib/logout.js +++ b/test/lib/logout.js @@ -17,13 +17,13 @@ const npmFetch = (url, opts) => { const mocks = { npmlog, 'npm-registry-fetch': npmFetch, - '../../lib/npm.js': { - flatOptions: _flatOptions, - config, - }, } -const logout = requireInject('../../lib/logout.js', mocks) +const Logout = requireInject('../../lib/logout.js', mocks) +const logout = new Logout({ + flatOptions: _flatOptions, + config, +}) test('token logout', async (t) => { t.plan(6) @@ -52,7 +52,7 @@ test('token logout', async (t) => { } await new Promise((res, rej) => { - logout([], (err) => { + logout.exec([], (err) => { t.ifError(err, 'should not error out') t.deepEqual( @@ -121,7 +121,7 @@ test('token scoped logout', async (t) => { } await new Promise((res, rej) => { - logout([], (err) => { + logout.exec([], (err) => { t.ifError(err, 'should not error out') t.deepEqual( @@ -174,7 +174,7 @@ test('user/pass logout', async (t) => { config.save = () => null await new Promise((res, rej) => { - logout([], (err) => { + logout.exec([], (err) => { t.ifError(err, 'should not error out') delete _flatOptions.username @@ -189,7 +189,7 @@ test('user/pass logout', async (t) => { }) test('missing credentials', (t) => { - logout([], (err) => { + logout.exec([], (err) => { t.match( err.message, /not logged in to https:\/\/registry.npmjs.org\/, so can't log out!/, @@ -228,7 +228,7 @@ test('ignore invalid scoped registry config', async (t) => { config.save = () => null await new Promise((res, rej) => { - logout([], (err) => { + logout.exec([], (err) => { t.ifError(err, 'should not error out') t.deepEqual( diff --git a/test/lib/ls.js b/test/lib/ls.js index b1df9067c..bd81776d5 100644 --- a/test/lib/ls.js +++ b/test/lib/ls.js @@ -106,28 +106,28 @@ const _flatOptions = { }, production: false, } -const ls = requireInject('../../lib/ls.js', { - '../../lib/npm.js': { - flatOptions: _flatOptions, - limit: { - fetch: 3, - }, - get prefix () { - return _flatOptions.prefix - }, - get globalDir () { - return globalDir - }, - config: { - get (key) { - return _flatOptions[key] - }, - }, - }, +const LS = requireInject('../../lib/ls.js', { '../../lib/utils/output.js': msg => { result = msg }, }) +const ls = new LS({ + flatOptions: _flatOptions, + limit: { + fetch: 3, + }, + get prefix () { + return _flatOptions.prefix + }, + get globalDir () { + return globalDir + }, + config: { + get (key) { + return _flatOptions[key] + }, + }, +}) const redactCwd = res => res && res.replace(/\\+/g, '/').replace(new RegExp(__dirname.replace(/\\+/g, '/'), 'gi'), '{CWD}') @@ -155,7 +155,7 @@ t.test('ls', (t) => { }), ...simpleNmFixture, }) - ls([], (err) => { + ls.exec([], (err) => { t.ifError(err, 'npm ls') t.matchSnapshot(redactCwd(result), 'should output tree representation of dependencies structure') t.end() @@ -166,7 +166,7 @@ t.test('ls', (t) => { prefix = t.testdir({ ...simpleNmFixture, }) - ls([], (err) => { + ls.exec([], (err) => { t.match(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code') t.matchSnapshot( redactCwd(err.message), @@ -188,7 +188,7 @@ t.test('ls', (t) => { }), ...simpleNmFixture, }) - ls([], (err) => { + ls.exec([], (err) => { t.equal(err.code, 'ELSPROBLEMS', 'should have error code') t.equal( redactCwd(err.message), @@ -213,7 +213,7 @@ t.test('ls', (t) => { }), ...simpleNmFixture, }) - ls(['lorem'], (err) => { + ls.exec(['lorem'], (err) => { t.ifError(err, 'npm ls') t.matchSnapshot(redactCwd(result), 'should output tree contaning only occurrences of filtered by package and colored output') _flatOptions.color = false @@ -235,7 +235,7 @@ t.test('ls', (t) => { }), ...simpleNmFixture, }) - ls(['.'], (err) => { + ls.exec(['.'], (err) => { t.ifError(err, 'should not throw on missing dep above current level') t.matchSnapshot(redactCwd(result), 'should output tree contaning only occurrences of filtered by package and colored output') _flatOptions.all = true @@ -256,7 +256,7 @@ t.test('ls', (t) => { }), ...simpleNmFixture, }) - ls(['bar'], (err) => { + ls.exec(['bar'], (err) => { t.ifError(err, 'npm ls') t.matchSnapshot(redactCwd(result), 'should output tree contaning only occurrences of filtered package and its ancestors') t.end() @@ -284,7 +284,7 @@ t.test('ls', (t) => { }, }, }) - ls(['bar@*', 'lorem@1.0.0'], (err) => { + ls.exec(['bar@*', 'lorem@1.0.0'], (err) => { t.ifError(err, 'npm ls') t.matchSnapshot(redactCwd(result), 'should output tree contaning only occurrences of multiple filtered packages and their ancestors') t.end() @@ -303,7 +303,7 @@ t.test('ls', (t) => { }), ...simpleNmFixture, }) - ls(['notadep'], (err) => { + ls.exec(['notadep'], (err) => { t.ifError(err, 'npm ls') t.matchSnapshot(redactCwd(result), 'should output tree containing no dependencies info') t.equal( @@ -330,7 +330,7 @@ t.test('ls', (t) => { }), ...simpleNmFixture, }) - ls([], (err) => { + ls.exec([], (err) => { t.ifError(err, 'npm ls') t.matchSnapshot(redactCwd(result), 'should output tree containing only top-level dependencies') _flatOptions.all = true @@ -353,7 +353,7 @@ t.test('ls', (t) => { }), ...simpleNmFixture, }) - ls([], (err) => { + ls.exec([], (err) => { t.ifError(err, 'npm ls') t.matchSnapshot(redactCwd(result), 'should output tree containing only top-level dependencies') _flatOptions.all = true @@ -414,7 +414,7 @@ t.test('ls', (t) => { }, }, }) - ls([], (err) => { + ls.exec([], (err) => { t.ifError(err, 'npm ls') t.matchSnapshot(redactCwd(result), 'should output tree containing top-level deps and their deps only') _flatOptions.all = true @@ -435,7 +435,7 @@ t.test('ls', (t) => { }), ...simpleNmFixture, }) - ls([], (err) => { + ls.exec([], (err) => { t.equal(err.code, 'ELSPROBLEMS', 'should have error code') t.equal( redactCwd(err.message).replace(/\r\n/g, '\n'), @@ -462,7 +462,7 @@ t.test('ls', (t) => { }), ...simpleNmFixture, }) - ls([], (err) => { + ls.exec([], (err) => { t.equal(err.code, 'ELSPROBLEMS', 'should have error code') t.matchSnapshot(redactCwd(result), 'should output tree containing color info') _flatOptions.color = false @@ -492,7 +492,7 @@ t.test('ls', (t) => { }), ...diffDepTypesNmFixture, }) - ls([], () => { + ls.exec([], () => { t.matchSnapshot(redactCwd(result), 'should output tree containing dev deps') _flatOptions.dev = false t.end() @@ -521,7 +521,7 @@ t.test('ls', (t) => { }), ...diffDepTypesNmFixture, }) - ls([], () => { + ls.exec([], () => { t.matchSnapshot(redactCwd(result), 'should output tree containing only development deps') _flatOptions.only = null t.end() @@ -560,7 +560,7 @@ t.test('ls', (t) => { ...diffDepTypesNmFixture.node_modules, }, }) - ls([], () => { + ls.exec([], () => { t.matchSnapshot(redactCwd(result), 'should output tree containing linked deps') _flatOptions.link = false t.end() @@ -596,7 +596,7 @@ t.test('ls', (t) => { b: t.fixture('symlink', '../b'), }, }) - ls([], () => { + ls.exec([], () => { t.matchSnapshot(redactCwd(result), 'should output tree containing linked deps') _flatOptions.link = false t.end() @@ -625,7 +625,7 @@ t.test('ls', (t) => { }), ...diffDepTypesNmFixture, }) - ls([], () => { + ls.exec([], () => { t.matchSnapshot(redactCwd(result), 'should output tree containing production deps') _flatOptions.production = false t.end() @@ -654,7 +654,7 @@ t.test('ls', (t) => { }), ...diffDepTypesNmFixture, }) - ls([], () => { + ls.exec([], () => { t.matchSnapshot(redactCwd(result), 'should output tree containing only prod deps') _flatOptions.only = null t.end() @@ -683,7 +683,7 @@ t.test('ls', (t) => { }), ...diffDepTypesNmFixture, }) - ls([], () => { + ls.exec([], () => { t.matchSnapshot(redactCwd(result), 'should output tree info with descriptions') _flatOptions.long = true t.end() @@ -714,7 +714,7 @@ t.test('ls', (t) => { }), ...diffDepTypesNmFixture, }) - ls([], () => { + ls.exec([], () => { t.matchSnapshot(redactCwd(result), 'should output tree containing top-level deps with descriptions') _flatOptions.all = true _flatOptions.depth = Infinity @@ -727,7 +727,7 @@ t.test('ls', (t) => { prefix = t.testdir({ 'package.json': '{broken json', }) - ls([], (err) => { + ls.exec([], (err) => { t.match(err, { code: 'EJSONPARSE' }, 'should throw EJSONPARSE error') t.matchSnapshot(redactCwd(result), 'should print empty result') t.end() @@ -736,7 +736,7 @@ t.test('ls', (t) => { t.test('empty location', (t) => { prefix = t.testdir({}) - ls([], (err) => { + ls.exec([], (err) => { t.ifError(err, 'should not error out on empty locations') t.matchSnapshot(redactCwd(result), 'should print empty result') t.end() @@ -764,7 +764,7 @@ t.test('ls', (t) => { }), ...diffDepTypesNmFixture, }) - ls([], () => { + ls.exec([], () => { t.matchSnapshot(redactCwd(result), 'should output tree signaling mismatching peer dep in problems') t.end() }) @@ -799,7 +799,7 @@ t.test('ls', (t) => { }, }, }) - ls([], () => { + ls.exec([], () => { t.matchSnapshot(redactCwd(result), 'should output tree signaling mismatching peer dep in problems') _flatOptions.color = false t.end() @@ -828,7 +828,7 @@ t.test('ls', (t) => { }, }, }) - ls([], (err) => { + ls.exec([], (err) => { t.match(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code') t.match(err.message, /missing: b@\^1.0.0/, 'should list missing dep problem') t.matchSnapshot(redactCwd(result), 'should output parseable signaling missing peer dep in problems') @@ -846,7 +846,7 @@ t.test('ls', (t) => { }, }), }) - ls([], (err) => { + ls.exec([], (err) => { t.match(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code') t.match(err.message, 'missing: peer-dep@*, required by test-npm-ls@1.0.0', 'should have missing peer-dep error msg') t.matchSnapshot(redactCwd(result), 'should output tree signaling missing peer dep in problems') @@ -877,7 +877,7 @@ t.test('ls', (t) => { }), ...diffDepTypesNmFixture, }) - ls([], (err) => { + ls.exec([], (err) => { t.match(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code') t.match(err.message, /invalid: optional-dep@1.0.0/, 'should have invalid dep error msg') t.matchSnapshot(redactCwd(result), 'should output tree with empty entry for missing optional deps') @@ -916,7 +916,7 @@ t.test('ls', (t) => { }, }, }) - ls([], (err) => { + ls.exec([], (err) => { t.ifError(err, 'npm ls') t.matchSnapshot(redactCwd(result), 'should print tree output containing deduped ref') t.end() @@ -954,7 +954,7 @@ t.test('ls', (t) => { }, }, }) - ls(['a'], (err) => { + ls.exec(['a'], (err) => { t.ifError(err, 'npm ls') t.matchSnapshot(redactCwd(result), 'should print tree output containing deduped ref') _flatOptions.color = false @@ -1002,7 +1002,7 @@ t.test('ls', (t) => { }, }, }) - ls([], (err) => { + ls.exec([], (err) => { t.ifError(err, 'npm ls') t.matchSnapshot(redactCwd(result), 'should print tree output containing deduped ref') t.end() @@ -1051,7 +1051,7 @@ t.test('ls', (t) => { }, }, }) - ls([], (err) => { + ls.exec([], (err) => { t.ifError(err, 'npm ls') t.matchSnapshot(redactCwd(result), 'should print tree output containing deduped ref') _flatOptions.all = true @@ -1101,7 +1101,7 @@ t.test('ls', (t) => { }, }, }) - ls(['@npmcli/b'], (err) => { + ls.exec(['@npmcli/b'], (err) => { t.ifError(err, 'npm ls') t.matchSnapshot(redactCwd(result), 'should print tree output containing deduped ref') _flatOptions.color = false @@ -1149,7 +1149,7 @@ t.test('ls', (t) => { }, }, }) - ls(['@npmcli/c'], (err) => { + ls.exec(['@npmcli/c'], (err) => { t.ifError(err, 'npm ls') t.matchSnapshot(redactCwd(result), 'should print tree output containing deduped ref') t.end() @@ -1193,7 +1193,7 @@ t.test('ls', (t) => { }, }) touchHiddenPackageLock(prefix) - ls([], () => { + ls.exec([], () => { t.matchSnapshot(redactCwd(result), 'should output tree containing aliases') t.end() }) @@ -1239,7 +1239,7 @@ t.test('ls', (t) => { }, }) touchHiddenPackageLock(prefix) - ls([], (err) => { + ls.exec([], (err) => { t.ifError(err, 'npm ls') t.matchSnapshot(redactCwd(result), 'should output tree containing git refs') t.end() @@ -1283,7 +1283,7 @@ t.test('ls', (t) => { }, }), }) - ls([], (err) => { + ls.exec([], (err) => { t.ifError(err, 'npm ls') t.matchSnapshot(redactCwd(result), 'should NOT print git refs in output tree') t.end() @@ -1338,7 +1338,7 @@ t.test('ls', (t) => { }, }) touchHiddenPackageLock(prefix) - ls([], () => { + ls.exec([], () => { t.matchSnapshot(redactCwd(result), 'should not be printed in tree output') t.end() }) @@ -1374,7 +1374,7 @@ t.test('ls', (t) => { // mimics lib/npm.js globalDir getter but pointing to fixtures globalDir = resolve(fixtures, 'node_modules') - ls([], () => { + ls.exec([], () => { t.matchSnapshot(redactCwd(result), 'should print tree and not mark top-level items extraneous') globalDir = 'MISSING_GLOBAL_DIR' _flatOptions.global = false @@ -1427,7 +1427,7 @@ t.test('ls', (t) => { }, }) - ls(['c'], (err) => { + ls.exec(['c'], (err) => { t.match(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code') t.matchSnapshot(redactCwd(result), 'should print tree and not duplicate child of missing items') t.end() @@ -1471,12 +1471,12 @@ t.test('ls', (t) => { }, }) - ls([], (err) => { + ls.exec([], (err) => { t.ifError(err, 'should NOT have ELSPROBLEMS error code') t.matchSnapshot(redactCwd(result), 'should list workspaces properly') // should also be able to filter out one of the workspaces - ls(['a'], (err) => { + ls.exec(['a'], (err) => { t.ifError(err, 'should NOT have ELSPROBLEMS error code when filter') t.matchSnapshot(redactCwd(result), 'should filter single workspace') @@ -1534,17 +1534,17 @@ t.test('ls', (t) => { }) t.plan(6) - ls(['a'], (err) => { + ls.exec(['a'], (err) => { t.ifError(err, 'should NOT have ELSPROBLEMS error code') t.matchSnapshot(redactCwd(result), 'should list a in top-level only') - ls(['d'], (err) => { + ls.exec(['d'], (err) => { t.ifError(err, 'should NOT have ELSPROBLEMS error code when filter') t.matchSnapshot(redactCwd(result), 'should print empty results msg') // if no --depth config is defined, should print path to dep _flatOptions.depth = null // default config value - ls(['d'], (err) => { + ls.exec(['d'], (err) => { t.ifError(err, 'should NOT have ELSPROBLEMS error code when filter') t.matchSnapshot(redactCwd(result), 'should print expected result') }) @@ -1576,7 +1576,7 @@ t.test('ls --parseable', (t) => { }), ...simpleNmFixture, }) - ls([], (err) => { + ls.exec([], (err) => { t.ifError(err, 'npm ls') t.matchSnapshot(redactCwd(result), 'should output parseable representation of dependencies structure') t.end() @@ -1587,7 +1587,7 @@ t.test('ls --parseable', (t) => { prefix = t.testdir({ ...simpleNmFixture, }) - ls([], (err) => { + ls.exec([], (err) => { t.match(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code') t.matchSnapshot( redactCwd(err.message), @@ -1609,7 +1609,7 @@ t.test('ls --parseable', (t) => { }), ...simpleNmFixture, }) - ls([], (err) => { + ls.exec([], (err) => { t.equal(err.code, 'ELSPROBLEMS', 'should have error code') t.matchSnapshot(redactCwd(result), 'should output containing problems info') t.end() @@ -1628,7 +1628,7 @@ t.test('ls --parseable', (t) => { }), ...simpleNmFixture, }) - ls(['lorem'], (err) => { + ls.exec(['lorem'], (err) => { t.ifError(err, 'npm ls') t.matchSnapshot(redactCwd(result), 'should output parseable contaning only occurrences of filtered by package') t.end() @@ -1647,7 +1647,7 @@ t.test('ls --parseable', (t) => { }), ...simpleNmFixture, }) - ls(['bar'], (err) => { + ls.exec(['bar'], (err) => { t.ifError(err, 'npm ls') t.matchSnapshot(redactCwd(result), 'should output parseable contaning only occurrences of filtered package') t.end() @@ -1675,7 +1675,7 @@ t.test('ls --parseable', (t) => { }, }, }) - ls(['bar@*', 'lorem@1.0.0'], (err) => { + ls.exec(['bar@*', 'lorem@1.0.0'], (err) => { t.ifError(err, 'npm ls') t.matchSnapshot(redactCwd(result), 'should output parseable contaning only occurrences of multiple filtered packages and their ancestors') t.end() @@ -1694,7 +1694,7 @@ t.test('ls --parseable', (t) => { }), ...simpleNmFixture, }) - ls(['notadep'], (err) => { + ls.exec(['notadep'], (err) => { t.ifError(err, 'npm ls') t.matchSnapshot(redactCwd(result), 'should output parseable output containing no dependencies info') t.equal( @@ -1721,7 +1721,7 @@ t.test('ls --parseable', (t) => { }), ...simpleNmFixture, }) - ls([], (err) => { + ls.exec([], (err) => { t.ifError(err, 'npm ls') t.matchSnapshot(redactCwd(result), 'should output parseable output containing only top-level dependencies') _flatOptions.all = true @@ -1744,7 +1744,7 @@ t.test('ls --parseable', (t) => { }), ...simpleNmFixture, }) - ls([], (err) => { + ls.exec([], (err) => { t.ifError(err, 'npm ls') t.matchSnapshot(redactCwd(result), 'should output tree containing only top-level dependencies') _flatOptions.all = true @@ -1767,7 +1767,7 @@ t.test('ls --parseable', (t) => { }), ...simpleNmFixture, }) - ls([], (err) => { + ls.exec([], (err) => { t.ifError(err, 'npm ls') t.matchSnapshot(redactCwd(result), 'should output parseable containing top-level deps and their deps only') _flatOptions.all = true @@ -1788,7 +1788,7 @@ t.test('ls --parseable', (t) => { }), ...simpleNmFixture, }) - ls([], (err) => { + ls.exec([], (err) => { t.match(err, { code: 'ELSPROBLEMS' }, 'should list dep problems') t.matchSnapshot(redactCwd(result), 'should output parseable containing top-level deps and their deps only') t.end() @@ -1817,7 +1817,7 @@ t.test('ls --parseable', (t) => { }), ...diffDepTypesNmFixture, }) - ls([], () => { + ls.exec([], () => { t.matchSnapshot(redactCwd(result), 'should output tree containing dev deps') _flatOptions.dev = false t.end() @@ -1846,7 +1846,7 @@ t.test('ls --parseable', (t) => { }), ...diffDepTypesNmFixture, }) - ls([], () => { + ls.exec([], () => { t.matchSnapshot(redactCwd(result), 'should output tree containing only development deps') _flatOptions.only = null t.end() @@ -1885,7 +1885,7 @@ t.test('ls --parseable', (t) => { ...diffDepTypesNmFixture.node_modules, }, }) - ls([], () => { + ls.exec([], () => { t.matchSnapshot(redactCwd(result), 'should output tree containing linked deps') _flatOptions.link = false t.end() @@ -1914,7 +1914,7 @@ t.test('ls --parseable', (t) => { }), ...diffDepTypesNmFixture, }) - ls([], () => { + ls.exec([], () => { t.matchSnapshot(redactCwd(result), 'should output tree containing production deps') _flatOptions.production = false t.end() @@ -1943,7 +1943,7 @@ t.test('ls --parseable', (t) => { }), ...diffDepTypesNmFixture, }) - ls([], () => { + ls.exec([], () => { t.matchSnapshot(redactCwd(result), 'should output tree containing only prod deps') _flatOptions.only = null t.end() @@ -1972,7 +1972,7 @@ t.test('ls --parseable', (t) => { }), ...diffDepTypesNmFixture, }) - ls([], () => { + ls.exec([], () => { t.matchSnapshot(redactCwd(result), 'should output tree info with descriptions') _flatOptions.long = true t.end() @@ -1990,7 +1990,7 @@ t.test('ls --parseable', (t) => { }), ...simpleNmFixture, }) - ls([], (err) => { + ls.exec([], (err) => { t.equal(err.code, 'ELSPROBLEMS', 'should have error code') t.match(redactCwd(err.message), 'extraneous: lorem@1.0.0 {CWD}/ls-ls-parseable--long-with-extraneous-deps/node_modules/lorem', 'should have error code') t.matchSnapshot(redactCwd(result), 'should output long parseable output with extraneous info') @@ -2011,7 +2011,7 @@ t.test('ls --parseable', (t) => { }), ...simpleNmFixture, }) - ls([], (err) => { + ls.exec([], (err) => { t.match(err, { code: 'ELSPROBLEMS' }, 'should list dep problems') t.matchSnapshot(redactCwd(result), 'should output parseable result containing EXTRANEOUS/INVALID labels') _flatOptions.long = false @@ -2051,7 +2051,7 @@ t.test('ls --parseable', (t) => { ...diffDepTypesNmFixture.node_modules, }, }) - ls([], (err) => { + ls.exec([], (err) => { t.ifError(err, 'npm ls') t.matchSnapshot(redactCwd(result), 'should output parseable results with symlink targets') _flatOptions.long = false @@ -2083,7 +2083,7 @@ t.test('ls --parseable', (t) => { }), ...diffDepTypesNmFixture, }) - ls([], () => { + ls.exec([], () => { t.matchSnapshot(redactCwd(result), 'should output tree containing top-level deps with descriptions') _flatOptions.all = true _flatOptions.depth = Infinity @@ -2096,7 +2096,7 @@ t.test('ls --parseable', (t) => { prefix = t.testdir({ 'package.json': '{broken json', }) - ls([], (err) => { + ls.exec([], (err) => { t.match(err, { code: 'EJSONPARSE' }, 'should throw EJSONPARSE error') t.matchSnapshot(redactCwd(result), 'should print empty result') t.end() @@ -2105,7 +2105,7 @@ t.test('ls --parseable', (t) => { t.test('empty location', (t) => { prefix = t.testdir({}) - ls([], (err) => { + ls.exec([], (err) => { t.ifError(err, 'should not error out on empty locations') t.matchSnapshot(redactCwd(result), 'should print empty result') t.end() @@ -2133,7 +2133,7 @@ t.test('ls --parseable', (t) => { }), ...diffDepTypesNmFixture, }) - ls([], () => { + ls.exec([], () => { t.matchSnapshot(redactCwd(result), 'should output parseable signaling missing peer dep in problems') t.end() }) @@ -2161,7 +2161,7 @@ t.test('ls --parseable', (t) => { }), ...diffDepTypesNmFixture, }) - ls([], (err) => { + ls.exec([], (err) => { t.match(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code') t.match(err.message, /invalid: optional-dep@1.0.0/, 'should have invalid dep error msg') t.matchSnapshot(redactCwd(result), 'should output parseable with empty entry for missing optional deps') @@ -2199,7 +2199,7 @@ t.test('ls --parseable', (t) => { }, }, }) - ls([], () => { + ls.exec([], () => { t.matchSnapshot(redactCwd(result), 'should print tree output omitting deduped ref') t.end() }) @@ -2238,7 +2238,7 @@ t.test('ls --parseable', (t) => { }, }) touchHiddenPackageLock(prefix) - ls([], () => { + ls.exec([], () => { t.matchSnapshot(redactCwd(result), 'should output tree containing aliases') t.end() }) @@ -2283,7 +2283,7 @@ t.test('ls --parseable', (t) => { }, }) touchHiddenPackageLock(prefix) - ls([], () => { + ls.exec([], () => { t.matchSnapshot(redactCwd(result), 'should output tree containing git refs') t.end() }) @@ -2337,7 +2337,7 @@ t.test('ls --parseable', (t) => { }, }) touchHiddenPackageLock(prefix) - ls([], () => { + ls.exec([], () => { t.matchSnapshot(redactCwd(result), 'should not be printed in tree output') t.end() }) @@ -2373,7 +2373,7 @@ t.test('ls --parseable', (t) => { // mimics lib/npm.js globalDir getter but pointing to fixtures globalDir = resolve(fixtures, 'node_modules') - ls([], () => { + ls.exec([], () => { t.matchSnapshot(redactCwd(result), 'should print parseable output for global deps') globalDir = 'MISSING_GLOBAL_DIR' _flatOptions.global = false @@ -2400,7 +2400,7 @@ t.test('ls --json', (t) => { }), ...simpleNmFixture, }) - ls([], (err) => { + ls.exec([], (err) => { t.ifError(err, 'npm ls') t.deepEqual( jsonParse(result), @@ -2431,7 +2431,7 @@ t.test('ls --json', (t) => { prefix = t.testdir({ ...simpleNmFixture, }) - ls([], (err) => { + ls.exec([], (err) => { t.match(err, { code: 'ELSPROBLEMS' }, 'should list dep problems') t.deepEqual( jsonParse(result), @@ -2487,7 +2487,7 @@ t.test('ls --json', (t) => { }), ...simpleNmFixture, }) - ls([], (err) => { + ls.exec([], (err) => { t.equal( redactCwd(err.message), 'extraneous: lorem@1.0.0 {CWD}/ls-ls-json-extraneous-deps/node_modules/lorem', @@ -2542,7 +2542,7 @@ t.test('ls --json', (t) => { }), ...simpleNmFixture, }) - ls(['lorem'], (err) => { + ls.exec(['lorem'], (err) => { t.ifError(err, 'npm ls') t.deepEqual( jsonParse(result), @@ -2578,7 +2578,7 @@ t.test('ls --json', (t) => { }), ...simpleNmFixture, }) - ls(['bar'], (err) => { + ls.exec(['bar'], (err) => { t.ifError(err, 'npm ls') t.deepEqual( jsonParse(result), @@ -2623,7 +2623,7 @@ t.test('ls --json', (t) => { }, }, }) - ls(['bar@*', 'lorem@1.0.0'], (err) => { + ls.exec(['bar@*', 'lorem@1.0.0'], (err) => { t.ifError(err, 'npm ls') t.deepEqual( jsonParse(result), @@ -2662,7 +2662,7 @@ t.test('ls --json', (t) => { }), ...simpleNmFixture, }) - ls(['notadep'], (err) => { + ls.exec(['notadep'], (err) => { t.ifError(err, 'npm ls') t.deepEqual( jsonParse(result), @@ -2696,7 +2696,7 @@ t.test('ls --json', (t) => { }), ...simpleNmFixture, }) - ls([], (err) => { + ls.exec([], (err) => { t.ifError(err, 'npm ls') t.deepEqual( jsonParse(result), @@ -2734,7 +2734,7 @@ t.test('ls --json', (t) => { }), ...simpleNmFixture, }) - ls([], (err) => { + ls.exec([], (err) => { t.ifError(err, 'npm ls') t.deepEqual( jsonParse(result), @@ -2772,7 +2772,7 @@ t.test('ls --json', (t) => { }), ...simpleNmFixture, }) - ls([], (err) => { + ls.exec([], (err) => { t.ifError(err, 'npm ls') t.deepEqual( jsonParse(result), @@ -2813,7 +2813,7 @@ t.test('ls --json', (t) => { }), ...simpleNmFixture, }) - ls([], (err) => { + ls.exec([], (err) => { t.match(err, { code: 'ELSPROBLEMS' }, 'should list dep problems') t.deepEqual( jsonParse(result), @@ -2882,7 +2882,7 @@ t.test('ls --json', (t) => { }), ...diffDepTypesNmFixture, }) - ls([], () => { + ls.exec([], () => { t.deepEqual( jsonParse(result), { @@ -2929,7 +2929,7 @@ t.test('ls --json', (t) => { }), ...diffDepTypesNmFixture, }) - ls([], () => { + ls.exec([], () => { t.deepEqual( jsonParse(result), { @@ -2986,7 +2986,7 @@ t.test('ls --json', (t) => { ...diffDepTypesNmFixture.node_modules, }, }) - ls([], () => { + ls.exec([], () => { t.deepEqual( jsonParse(result), { @@ -3028,7 +3028,7 @@ t.test('ls --json', (t) => { }), ...diffDepTypesNmFixture, }) - ls([], () => { + ls.exec([], () => { t.deepEqual( jsonParse(result), { @@ -3069,7 +3069,7 @@ t.test('ls --json', (t) => { }), ...diffDepTypesNmFixture, }) - ls([], () => { + ls.exec([], () => { t.deepEqual( jsonParse(result), { @@ -3182,7 +3182,7 @@ t.test('ls --json', (t) => { }, }), }) - ls([], () => { + ls.exec([], () => { t.deepEqual( jsonParse(result), { @@ -3239,7 +3239,7 @@ t.test('ls --json', (t) => { }), ...diffDepTypesNmFixture, }) - ls([], () => { + ls.exec([], () => { t.deepEqual( jsonParse(result), { @@ -3377,7 +3377,7 @@ t.test('ls --json', (t) => { }), ...diffDepTypesNmFixture, }) - ls([], () => { + ls.exec([], () => { t.deepEqual( jsonParse(result), { @@ -3460,7 +3460,7 @@ t.test('ls --json', (t) => { prefix = t.testdir({ 'package.json': '{broken json', }) - ls([], (err) => { + ls.exec([], (err) => { t.match(err.message, 'Failed to parse root package.json', 'should have missin root package.json msg') t.match(err.code, 'EJSONPARSE', 'should have EJSONPARSE error code') t.deepEqual( @@ -3479,7 +3479,7 @@ t.test('ls --json', (t) => { t.test('empty location', (t) => { prefix = t.testdir({}) - ls([], (err) => { + ls.exec([], (err) => { t.ifError(err, 'should not error out on empty locations') t.deepEqual( jsonParse(result), @@ -3511,7 +3511,7 @@ t.test('ls --json', (t) => { }), ...diffDepTypesNmFixture, }) - ls([], (err) => { + ls.exec([], (err) => { t.match(err.code, 'ELSPROBLEMS', 'Should have ELSPROBLEMS error code') t.deepEqual( jsonParse(result), @@ -3571,7 +3571,7 @@ t.test('ls --json', (t) => { }), ...diffDepTypesNmFixture, }) - ls([], (err) => { + ls.exec([], (err) => { t.match(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code') t.match(err.message, /invalid: optional-dep@1.0.0/, 'should have invalid dep error msg') t.deepEqual( @@ -3643,7 +3643,7 @@ t.test('ls --json', (t) => { }, }, }) - ls([], () => { + ls.exec([], () => { t.deepEqual( jsonParse(result), { @@ -3701,7 +3701,7 @@ t.test('ls --json', (t) => { }, }) touchHiddenPackageLock(prefix) - ls([], () => { + ls.exec([], () => { t.deepEqual( jsonParse(result), { @@ -3761,7 +3761,7 @@ t.test('ls --json', (t) => { }, }) touchHiddenPackageLock(prefix) - ls([], () => { + ls.exec([], () => { t.deepEqual( jsonParse(result), { @@ -3845,7 +3845,7 @@ t.test('ls --json', (t) => { }, }) touchHiddenPackageLock(prefix) - ls([], () => { + ls.exec([], () => { t.deepEqual( jsonParse(result), { @@ -3870,7 +3870,7 @@ t.test('ls --json', (t) => { version: '1.0.0', }), }) - ls([], () => { + ls.exec([], () => { t.deepEqual( jsonParse(result), { @@ -3913,7 +3913,7 @@ t.test('ls --json', (t) => { // mimics lib/npm.js globalDir getter but pointing to fixtures globalDir = resolve(fixtures, 'node_modules') - ls([], () => { + ls.exec([], () => { t.deepEqual( jsonParse(result), { diff --git a/test/lib/npm.js b/test/lib/npm.js index 9fd9888b9..18bed36de 100644 --- a/test/lib/npm.js +++ b/test/lib/npm.js @@ -16,7 +16,7 @@ for (const env of Object.keys(process.env).filter(e => /^npm_/.test(e))) { 'should match "npm test" or "npm run test"' ) } else - t.match(process.env[env], 'run-script') + t.match(process.env[env], /^(run)|(run-script)|(exec)$/) } delete process.env[env] } @@ -310,10 +310,10 @@ t.test('npm.load', t => { if (er) throw er - t.same(consoleLogs, [[require('../../lib/ls.js').usage]], 'print usage') + t.same(consoleLogs, [[npm.commands.ll.usage]], 'print usage') consoleLogs.length = 0 npm.config.set('usage', false) - t.equal(npm.commands.ll, npm.commands.la, 'same command, different name') + t.equal(npm.commands.ll, npm.commands.ll, 'same command, different name') logs.length = 0 }) @@ -352,13 +352,15 @@ t.test('npm.load', t => { t.test('loading as main will load the cli', t => { const { spawn } = require('child_process') const npm = require.resolve('../../lib/npm.js') + const LS = require('../../lib/ls.js') + const ls = new LS({}) const p = spawn(process.execPath, [npm, 'ls', '-h']) const out = [] p.stdout.on('data', c => out.push(c)) p.on('close', (code, signal) => { t.equal(code, 0) t.equal(signal, null) - t.equal(Buffer.concat(out).toString().trim(), require('../../lib/ls.js').usage) + t.equal(Buffer.concat(out).toString().trim(), ls.usage) t.end() }) }) diff --git a/test/lib/org.js b/test/lib/org.js index 1e8aabc1d..d21df85d6 100644 --- a/test/lib/org.js +++ b/test/lib/org.js @@ -39,14 +39,14 @@ const libnpmorg = { }, } -const org = requireInject('../../lib/org.js', { - '../../lib/npm.js': npm, +const Org = requireInject('../../lib/org.js', { '../../lib/utils/otplease.js': async (opts, fn) => fn(opts), '../../lib/utils/output.js': (msg) => { output.push(msg) }, libnpmorg, }) +const org = new Org(npm) test('completion', async t => { const completion = (argv) => @@ -67,7 +67,7 @@ test('completion', async t => { }) test('npm org - invalid subcommand', t => { - return org(['foo'], (err) => { + org.exec(['foo'], (err) => { t.match(err, /npm org set/, 'prints usage information') t.end() }) @@ -79,7 +79,7 @@ test('npm org add', t => { output.length = 0 }) - return org(['add', 'orgname', 'username'], (err) => { + org.exec(['add', 'orgname', 'username'], (err) => { if (err) throw err @@ -100,7 +100,7 @@ test('npm org add - no org', t => { output.length = 0 }) - return org(['add', '', 'username'], (err) => { + org.exec(['add', '', 'username'], (err) => { t.match(err, /`orgname` is required/, 'returns the correct error') t.end() }) @@ -112,7 +112,7 @@ test('npm org add - no user', t => { output.length = 0 }) - return org(['add', 'orgname', ''], (err) => { + org.exec(['add', 'orgname', ''], (err) => { t.match(err, /`username` is required/, 'returns the correct error') t.end() }) @@ -124,7 +124,7 @@ test('npm org add - invalid role', t => { output.length = 0 }) - return org(['add', 'orgname', 'username', 'person'], (err) => { + org.exec(['add', 'orgname', 'username', 'person'], (err) => { t.match(err, /`role` must be one of/, 'returns the correct error') t.end() }) @@ -138,7 +138,7 @@ test('npm org add - more users', t => { output.length = 0 }) - return org(['add', 'orgname', 'username'], (err) => { + org.exec(['add', 'orgname', 'username'], (err) => { if (err) throw err @@ -161,7 +161,7 @@ test('npm org add - json output', t => { output.length = 0 }) - return org(['add', 'orgname', 'username'], (err) => { + org.exec(['add', 'orgname', 'username'], (err) => { if (err) throw err @@ -191,7 +191,7 @@ test('npm org add - parseable output', t => { output.length = 0 }) - return org(['add', 'orgname', 'username'], (err) => { + org.exec(['add', 'orgname', 'username'], (err) => { if (err) throw err @@ -217,7 +217,7 @@ test('npm org add - silent output', t => { output.length = 0 }) - return org(['add', 'orgname', 'username'], (err) => { + org.exec(['add', 'orgname', 'username'], (err) => { if (err) throw err @@ -239,7 +239,7 @@ test('npm org rm', t => { output.length = 0 }) - return org(['rm', 'orgname', 'username'], (err) => { + org.exec(['rm', 'orgname', 'username'], (err) => { if (err) throw err @@ -264,7 +264,7 @@ test('npm org rm - no org', t => { output.length = 0 }) - return org(['rm', '', 'username'], (err) => { + org.exec(['rm', '', 'username'], (err) => { t.match(err, /`orgname` is required/, 'threw the correct error') t.end() }) @@ -277,7 +277,7 @@ test('npm org rm - no user', t => { output.length = 0 }) - return org(['rm', 'orgname'], (err) => { + org.exec(['rm', 'orgname'], (err) => { t.match(err, /`username` is required/, 'threw the correct error') t.end() }) @@ -295,7 +295,7 @@ test('npm org rm - one user left', t => { output.length = 0 }) - return org(['rm', 'orgname', 'username'], (err) => { + org.exec(['rm', 'orgname', 'username'], (err) => { if (err) throw err @@ -322,7 +322,7 @@ test('npm org rm - json output', t => { output.length = 0 }) - return org(['rm', 'orgname', 'username'], (err) => { + org.exec(['rm', 'orgname', 'username'], (err) => { if (err) throw err @@ -354,7 +354,7 @@ test('npm org rm - parseable output', t => { output.length = 0 }) - return org(['rm', 'orgname', 'username'], (err) => { + org.exec(['rm', 'orgname', 'username'], (err) => { if (err) throw err @@ -384,7 +384,7 @@ test('npm org rm - silent output', t => { output.length = 0 }) - return org(['rm', 'orgname', 'username'], (err) => { + org.exec(['rm', 'orgname', 'username'], (err) => { if (err) throw err @@ -414,7 +414,7 @@ test('npm org ls', t => { output.length = 0 }) - return org(['ls', 'orgname'], (err) => { + org.exec(['ls', 'orgname'], (err) => { if (err) throw err @@ -441,7 +441,7 @@ test('npm org ls - user filter', t => { output.length = 0 }) - return org(['ls', 'orgname', 'username'], (err) => { + org.exec(['ls', 'orgname', 'username'], (err) => { if (err) throw err @@ -466,7 +466,7 @@ test('npm org ls - user filter, missing user', t => { output.length = 0 }) - return org(['ls', 'orgname', 'username'], (err) => { + org.exec(['ls', 'orgname', 'username'], (err) => { if (err) throw err @@ -487,7 +487,7 @@ test('npm org ls - no org', t => { output.length = 0 }) - return org(['ls'], (err) => { + org.exec(['ls'], (err) => { t.match(err, /`orgname` is required/, 'throws the correct error') t.end() }) @@ -507,7 +507,7 @@ test('npm org ls - json output', t => { output.length = 0 }) - return org(['ls', 'orgname'], (err) => { + org.exec(['ls', 'orgname'], (err) => { if (err) throw err @@ -534,7 +534,7 @@ test('npm org ls - parseable output', t => { output.length = 0 }) - return org(['ls', 'orgname'], (err) => { + org.exec(['ls', 'orgname'], (err) => { if (err) throw err @@ -566,7 +566,7 @@ test('npm org ls - silent output', t => { output.length = 0 }) - return org(['ls', 'orgname'], (err) => { + org.exec(['ls', 'orgname'], (err) => { if (err) throw err diff --git a/test/lib/outdated.js b/test/lib/outdated.js index da53b6031..aa8a1bcb6 100644 --- a/test/lib/outdated.js +++ b/test/lib/outdated.js @@ -92,19 +92,18 @@ const globalDir = t.testdir({ }, }) -const outdated = (dir, opts) => requireInject( - '../../lib/outdated.js', - { - '../../lib/npm.js': { - prefix: dir, - globalDir: `${globalDir}/node_modules`, - flatOptions: opts, - }, +const outdated = (dir, opts) => { + const Outdated = requireInject('../../lib/outdated.js', { pacote: { packument, }, - } -) + }) + return new Outdated({ + prefix: dir, + globalDir: `${globalDir}/node_modules`, + flatOptions: opts, + }) +} t.beforeEach(cleanLogs) @@ -180,7 +179,7 @@ t.test('should display outdated deps', t => { t.test('outdated global', t => { outdated(null, { global: true, - })([], () => { + }).exec([], () => { t.matchSnapshot(logs) t.end() }) @@ -190,7 +189,7 @@ t.test('should display outdated deps', t => { outdated(testDir, { global: false, color: true, - })([], () => { + }).exec([], () => { t.matchSnapshot(logs) t.end() }) @@ -201,7 +200,7 @@ t.test('should display outdated deps', t => { global: false, color: true, omit: ['dev'], - })([], () => { + }).exec([], () => { t.matchSnapshot(logs) t.end() }) @@ -212,7 +211,7 @@ t.test('should display outdated deps', t => { global: false, color: true, omit: ['dev', 'peer'], - })([], () => { + }).exec([], () => { t.matchSnapshot(logs) t.end() }) @@ -223,7 +222,7 @@ t.test('should display outdated deps', t => { global: false, color: true, omit: ['prod'], - })([], () => { + }).exec([], () => { t.matchSnapshot(logs) t.end() }) @@ -233,7 +232,7 @@ t.test('should display outdated deps', t => { outdated(testDir, { global: false, long: true, - })([], () => { + }).exec([], () => { t.matchSnapshot(logs) t.end() }) @@ -243,7 +242,7 @@ t.test('should display outdated deps', t => { outdated(testDir, { global: false, json: true, - })([], () => { + }).exec([], () => { t.matchSnapshot(logs) t.end() }) @@ -254,7 +253,7 @@ t.test('should display outdated deps', t => { global: false, json: true, long: true, - })([], () => { + }).exec([], () => { t.matchSnapshot(logs) t.end() }) @@ -264,7 +263,7 @@ t.test('should display outdated deps', t => { outdated(testDir, { global: false, parseable: true, - })([], () => { + }).exec([], () => { t.matchSnapshot(logs) t.end() }) @@ -275,7 +274,7 @@ t.test('should display outdated deps', t => { global: false, parseable: true, long: true, - })([], () => { + }).exec([], () => { t.matchSnapshot(logs) t.end() }) @@ -284,7 +283,7 @@ t.test('should display outdated deps', t => { t.test('outdated --all', t => { outdated(testDir, { all: true, - })([], () => { + }).exec([], () => { t.matchSnapshot(logs) t.end() }) @@ -293,7 +292,7 @@ t.test('should display outdated deps', t => { t.test('outdated specific dep', t => { outdated(testDir, { global: false, - })(['alpha'], () => { + }).exec(['alpha'], () => { t.matchSnapshot(logs) t.end() }) @@ -323,7 +322,7 @@ t.test('should return if no outdated deps', t => { outdated(testDir, { global: false, - })([], () => { + }).exec([], () => { t.equals(logs.length, 0, 'no logs') t.end() }) @@ -350,7 +349,7 @@ t.test('throws if error with a dep', t => { outdated(testDir, { global: false, - })([], (err) => { + }).exec([], (err) => { t.equals(err.message, 'There is an error with this package.') t.end() }) @@ -370,7 +369,7 @@ t.test('should skip missing non-prod deps', t => { outdated(testDir, { global: false, - })([], () => { + }).exec([], () => { t.equals(logs.length, 0, 'no logs') t.end() }) @@ -395,7 +394,7 @@ t.test('should skip invalid pkg ranges', t => { }, }) - outdated(testDir, {})([], () => { + outdated(testDir, {}).exec([], () => { t.equals(logs.length, 0, 'no logs') t.end() }) @@ -420,7 +419,7 @@ t.test('should skip git specs', t => { }, }) - outdated(testDir, {})([], () => { + outdated(testDir, {}).exec([], () => { t.equals(logs.length, 0, 'no logs') t.end() }) diff --git a/test/lib/owner.js b/test/lib/owner.js index aa5e3ee63..4f8f43088 100644 --- a/test/lib/owner.js +++ b/test/lib/owner.js @@ -15,7 +15,6 @@ const mocks = { npmlog, 'npm-registry-fetch': npmFetch, pacote, - '../../lib/npm.js': npm, '../../lib/utils/output.js': (...msg) => { result += msg.join('\n') }, @@ -31,7 +30,8 @@ const npmcliMaintainers = [ { email: 'i@izs.me', name: 'isaacs' }, ] -const owner = requireInject('../../lib/owner.js', mocks) +const Owner = requireInject('../../lib/owner.js', mocks) +const owner = new Owner(npm) t.test('owner no args', t => { result = '' @@ -39,7 +39,7 @@ t.test('owner no args', t => { result = '' }) - owner([], err => { + owner.exec([], err => { t.equal( err.message, 'usage instructions', @@ -73,7 +73,7 @@ t.test('owner ls no args', t => { readLocalPkgResponse = null }) - owner(['ls'], err => { + owner.exec(['ls'], err => { t.ifError(err, 'npm owner ls no args') t.matchSnapshot(result, 'should output owners of cwd package') }) @@ -86,7 +86,7 @@ t.test('owner ls no args no cwd package', t => { npmlog.error = noop }) - owner(['ls'], err => { + owner.exec(['ls'], err => { t.equal( err.message, 'usage instructions', @@ -115,7 +115,7 @@ t.test('owner ls fails to retrieve packument', t => { pacote.packument = noop }) - owner(['ls'], err => { + owner.exec(['ls'], err => { t.match( err, /ERR/, @@ -145,7 +145,7 @@ t.test('owner ls <pkg>', t => { pacote.packument = noop }) - owner(['ls', '@npmcli/map-workspaces'], err => { + owner.exec(['ls', '@npmcli/map-workspaces'], err => { t.ifError(err, 'npm owner ls <pkg>') t.matchSnapshot(result, 'should output owners of <pkg>') }) @@ -161,7 +161,7 @@ t.test('owner ls <pkg> no maintainers', t => { pacote.packument = noop }) - owner(['ls', '@npmcli/map-workspaces'], err => { + owner.exec(['ls', '@npmcli/map-workspaces'], err => { t.ifError(err, 'npm owner ls <pkg> no maintainers') t.equal(result, 'no admin found', 'should output no admint found msg') t.end() @@ -232,7 +232,7 @@ t.test('owner add <user> <pkg>', t => { pacote.packument = noop }) - owner(['add', 'foo', '@npmcli/map-workspaces'], err => { + owner.exec(['add', 'foo', '@npmcli/map-workspaces'], err => { t.ifError(err, 'npm owner add <user> <pkg>') t.equal(result, '+ foo (@npmcli/map-workspaces)', 'should output add result') }) @@ -265,7 +265,7 @@ t.test('owner add <user> cwd package', t => { pacote.packument = noop }) - owner(['add', 'foo'], err => { + owner.exec(['add', 'foo'], err => { t.ifError(err, 'npm owner add <user> cwd package') t.equal(result, '+ foo (@npmcli/map-workspaces)', 'should output add result') t.end() @@ -308,7 +308,7 @@ t.test('owner add <user> <pkg> already an owner', t => { pacote.packument = noop }) - owner(['add', 'ruyadorno', '@npmcli/map-workspaces'], err => { + owner.exec(['add', 'ruyadorno', '@npmcli/map-workspaces'], err => { t.ifError(err, 'npm owner add <user> <pkg> already an owner') }) }) @@ -336,7 +336,7 @@ t.test('owner add <user> <pkg> fails to retrieve user', t => { pacote.packument = noop }) - owner(['add', 'foo', '@npmcli/map-workspaces'], err => { + owner.exec(['add', 'foo', '@npmcli/map-workspaces'], err => { t.match( err, /Error: Couldn't get user data for foo: {"ok":false}/, @@ -377,7 +377,7 @@ t.test('owner add <user> <pkg> fails to PUT updates', t => { pacote.packument = noop }) - owner(['add', 'foo', '@npmcli/map-workspaces'], err => { + owner.exec(['add', 'foo', '@npmcli/map-workspaces'], err => { t.match( err.message, /Failed to update package/, @@ -417,7 +417,7 @@ t.test('owner add <user> <pkg> fails to retrieve user info', t => { pacote.packument = noop }) - owner(['add', 'foo', '@npmcli/map-workspaces'], err => { + owner.exec(['add', 'foo', '@npmcli/map-workspaces'], err => { t.match( err.message, "I'm a teapot", @@ -453,7 +453,7 @@ t.test('owner add <user> <pkg> no previous maintainers property from server', t pacote.packument = noop }) - owner(['add', 'foo', '@npmcli/no-owners-pkg'], err => { + owner.exec(['add', 'foo', '@npmcli/no-owners-pkg'], err => { t.ifError(err, 'npm owner add <user> <pkg>') t.equal(result, '+ foo (@npmcli/no-owners-pkg)', 'should output add result') t.end() @@ -466,7 +466,7 @@ t.test('owner add no user', t => { result = '' }) - owner(['add'], err => { + owner.exec(['add'], err => { t.equal( err.message, 'usage instructions', @@ -482,7 +482,7 @@ t.test('owner add <user> no cwd package', t => { result = '' }) - owner(['add', 'foo'], err => { + owner.exec(['add', 'foo'], err => { t.equal( err.message, 'usage instructions', @@ -549,7 +549,7 @@ t.test('owner rm <user> <pkg>', t => { pacote.packument = noop }) - owner(['rm', 'ruyadorno', '@npmcli/map-workspaces'], err => { + owner.exec(['rm', 'ruyadorno', '@npmcli/map-workspaces'], err => { t.ifError(err, 'npm owner rm <user> <pkg>') t.equal(result, '- ruyadorno (@npmcli/map-workspaces)', 'should output rm result') }) @@ -589,7 +589,7 @@ t.test('owner rm <user> <pkg> not a current owner', t => { pacote.packument = noop }) - owner(['rm', 'foo', '@npmcli/map-workspaces'], err => { + owner.exec(['rm', 'foo', '@npmcli/map-workspaces'], err => { t.ifError(err, 'npm owner rm <user> <pkg> not a current owner') }) }) @@ -621,7 +621,7 @@ t.test('owner rm <user> cwd package', t => { pacote.packument = noop }) - owner(['rm', 'ruyadorno'], err => { + owner.exec(['rm', 'ruyadorno'], err => { t.ifError(err, 'npm owner rm <user> cwd package') t.equal(result, '- ruyadorno (@npmcli/map-workspaces)', 'should output rm result') t.end() @@ -656,7 +656,7 @@ t.test('owner rm <user> only user', t => { pacote.packument = noop }) - owner(['rm', 'ruyadorno'], err => { + owner.exec(['rm', 'ruyadorno'], err => { t.equal( err.message, 'Cannot remove all owners of a package. Add someone else first.', @@ -673,7 +673,7 @@ t.test('owner rm no user', t => { result = '' }) - owner(['rm'], err => { + owner.exec(['rm'], err => { t.equal( err.message, 'usage instructions', @@ -689,7 +689,7 @@ t.test('owner rm <user> no cwd package', t => { result = '' }) - owner(['rm', 'foo'], err => { + owner.exec(['rm', 'foo'], err => { t.equal( err.message, 'usage instructions', @@ -700,10 +700,8 @@ t.test('owner rm <user> no cwd package', t => { }) t.test('completion', async t => { - const { completion } = owner - const testComp = async (argv, expect) => { - const res = await completion({ conf: { argv: { remain: argv } } }) + const res = await owner.completion({ conf: { argv: { remain: argv } } }) t.strictSame(res, expect, argv.join(' ')) } @@ -730,7 +728,7 @@ t.test('completion', async t => { pacote.packument = noop }) - const res = await completion({ conf: { argv: { remain: ['npm', 'owner', 'rm'] } } }) + const res = await owner.completion({ conf: { argv: { remain: ['npm', 'owner', 'rm'] } } }) t.strictSame(res, ['nlf', 'ruyadorno', 'darcyclarke', 'isaacs'], 'should return list of current owners' @@ -738,7 +736,7 @@ t.test('completion', async t => { }) t.test('completion npm owner rm no cwd package', async t => { - const res = await completion({ conf: { argv: { remain: ['npm', 'owner', 'rm'] } } }) + const res = await owner.completion({ conf: { argv: { remain: ['npm', 'owner', 'rm'] } } }) t.strictSame(res, [], 'should have no owners to autocomplete if not cwd package') t.end() }) @@ -757,7 +755,7 @@ t.test('completion', async t => { pacote.packument = noop }) - const res = await completion({ conf: { argv: { remain: ['npm', 'owner', 'rm'] } } }) + const res = await owner.completion({ conf: { argv: { remain: ['npm', 'owner', 'rm'] } } }) t.strictSame(res, [], 'should return no owners if not found') }) diff --git a/test/lib/pack.js b/test/lib/pack.js index 851174d25..73a19baa3 100644 --- a/test/lib/pack.js +++ b/test/lib/pack.js @@ -17,15 +17,8 @@ t.afterEach(cb => { }) t.test('should pack current directory with no arguments', (t) => { - const pack = requireInject('../../lib/pack.js', { + const Pack = requireInject('../../lib/pack.js', { '../../lib/utils/output.js': output, - '../../lib/npm.js': { - flatOptions: { - unicode: false, - json: false, - dryRun: false, - }, - }, libnpmpack, npmlog: { notice: () => {}, @@ -33,13 +26,21 @@ t.test('should pack current directory with no arguments', (t) => { clearProgress: () => {}, }, }) + const pack = new Pack({ + flatOptions: { + unicode: false, + json: false, + dryRun: false, + }, + }) - return pack([], er => { + pack.exec([], er => { if (er) throw er const filename = `npm-${require('../../package.json').version}.tgz` t.strictSame(OUTPUT, [[filename]]) + t.end() }) }) @@ -51,15 +52,8 @@ t.test('should pack given directory', (t) => { }, null, 2), }) - const pack = requireInject('../../lib/pack.js', { + const Pack = requireInject('../../lib/pack.js', { '../../lib/utils/output.js': output, - '../../lib/npm.js': { - flatOptions: { - unicode: true, - json: true, - dryRun: true, - }, - }, libnpmpack, npmlog: { notice: () => {}, @@ -67,13 +61,21 @@ t.test('should pack given directory', (t) => { clearProgress: () => {}, }, }) + const pack = new Pack({ + flatOptions: { + unicode: true, + json: true, + dryRun: true, + }, + }) - return pack([testDir], er => { + pack.exec([testDir], er => { if (er) throw er const filename = 'my-cool-pkg-1.0.0.tgz' t.strictSame(OUTPUT, [[filename]]) + t.end() }) }) @@ -85,15 +87,8 @@ t.test('should pack given directory for scoped package', (t) => { }, null, 2), }) - const pack = requireInject('../../lib/pack.js', { + const Pack = requireInject('../../lib/pack.js', { '../../lib/utils/output.js': output, - '../../lib/npm.js': { - flatOptions: { - unicode: true, - json: true, - dryRun: true, - }, - }, libnpmpack, npmlog: { notice: () => {}, @@ -101,18 +96,26 @@ t.test('should pack given directory for scoped package', (t) => { clearProgress: () => {}, }, }) + const pack = new Pack({ + flatOptions: { + unicode: true, + json: true, + dryRun: true, + }, + }) - return pack([testDir], er => { + return pack.exec([testDir], er => { if (er) throw er const filename = 'cool-my-pkg-1.0.0.tgz' t.strictSame(OUTPUT, [[filename]]) + t.end() }) }) t.test('should log pack contents', (t) => { - const pack = requireInject('../../lib/pack.js', { + const Pack = requireInject('../../lib/pack.js', { '../../lib/utils/output.js': output, '../../lib/utils/tar.js': { ...require('../../lib/utils/tar.js'), @@ -120,13 +123,6 @@ t.test('should log pack contents', (t) => { t.ok(true, 'logTar is called') }, }, - '../../lib/npm.js': { - flatOptions: { - unicode: false, - json: false, - dryRun: false, - }, - }, libnpmpack, npmlog: { notice: () => {}, @@ -134,12 +130,20 @@ t.test('should log pack contents', (t) => { clearProgress: () => {}, }, }) + const pack = new Pack({ + flatOptions: { + unicode: false, + json: false, + dryRun: false, + }, + }) - return pack([], er => { + pack.exec([], er => { if (er) throw er const filename = `npm-${require('../../package.json').version}.tgz` t.strictSame(OUTPUT, [[filename]]) + t.end() }) }) diff --git a/test/lib/ping.js b/test/lib/ping.js index a185919dd..cf4753074 100644 --- a/test/lib/ping.js +++ b/test/lib/ping.js @@ -6,8 +6,7 @@ test('pings', (t) => { const flatOptions = { registry: 'https://registry.npmjs.org' } let noticeCalls = 0 - const ping = requireInject('../../lib/ping.js', { - '../../lib/npm.js': { flatOptions }, + const Ping = requireInject('../../lib/ping.js', { '../../lib/utils/ping.js': function (spec) { t.equal(spec, flatOptions, 'passes flatOptions') return {} @@ -25,8 +24,9 @@ test('pings', (t) => { }, }, }) + const ping = new Ping({ flatOptions }) - ping([], (err) => { + ping.exec([], (err) => { t.equal(noticeCalls, 2, 'should have logged 2 lines') t.ifError(err, 'npm ping') t.ok('should be able to ping') @@ -39,8 +39,7 @@ test('pings and logs details', (t) => { const flatOptions = { registry: 'https://registry.npmjs.org' } const details = { extra: 'data' } let noticeCalls = 0 - const ping = requireInject('../../lib/ping.js', { - '../../lib/npm.js': { flatOptions }, + const Ping = requireInject('../../lib/ping.js', { '../../lib/utils/ping.js': function (spec) { t.equal(spec, flatOptions, 'passes flatOptions') return details @@ -62,8 +61,9 @@ test('pings and logs details', (t) => { }, }, }) + const ping = new Ping({ flatOptions }) - ping([], (err) => { + ping.exec([], (err) => { t.equal(noticeCalls, 3, 'should have logged 3 lines') t.ifError(err, 'npm ping') t.ok('should be able to ping') @@ -76,8 +76,7 @@ test('pings and returns json', (t) => { const flatOptions = { registry: 'https://registry.npmjs.org', json: true } const details = { extra: 'data' } let noticeCalls = 0 - const ping = requireInject('../../lib/ping.js', { - '../../lib/npm.js': { flatOptions }, + const Ping = requireInject('../../lib/ping.js', { '../../lib/utils/ping.js': function (spec) { t.equal(spec, flatOptions, 'passes flatOptions') return details @@ -101,8 +100,9 @@ test('pings and returns json', (t) => { }, }, }) + const ping = new Ping({ flatOptions }) - ping([], (err) => { + ping.exec([], (err) => { t.equal(noticeCalls, 2, 'should have logged 2 lines') t.ifError(err, 'npm ping') t.ok('should be able to ping') diff --git a/test/lib/prefix.js b/test/lib/prefix.js index 83e2d6368..dfb50f174 100644 --- a/test/lib/prefix.js +++ b/test/lib/prefix.js @@ -5,14 +5,14 @@ test('prefix', (t) => { t.plan(3) const dir = '/prefix/dir' - const prefix = requireInject('../../lib/prefix.js', { - '../../lib/npm.js': { prefix: dir }, + const Prefix = requireInject('../../lib/prefix.js', { '../../lib/utils/output.js': (output) => { t.equal(output, dir, 'prints the correct directory') }, }) + const prefix = new Prefix({ prefix: dir }) - prefix([], (err) => { + prefix.exec([], (err) => { t.ifError(err, 'npm prefix') t.ok('should have printed directory') }) diff --git a/test/lib/profile.js b/test/lib/profile.js index 3b2e14003..743ba2d68 100644 --- a/test/lib/profile.js +++ b/test/lib/profile.js @@ -32,7 +32,6 @@ const mocks = { .join('\n') } }, - '../../lib/npm.js': npm, '../../lib/utils/output.js': (...msg) => { result += msg.join('\n') }, @@ -68,10 +67,11 @@ t.afterEach(cb => { cb() }) -const profile = requireInject('../../lib/profile.js', mocks) +const Profile = requireInject('../../lib/profile.js', mocks) +const profile = new Profile(npm) t.test('no args', t => { - profile([], err => { + profile.exec([], err => { t.match( err, /usage instructions/, @@ -88,13 +88,14 @@ t.test('profile get no args', t => { }, } - const profile = requireInject('../../lib/profile.js', { + const Profile = requireInject('../../lib/profile.js', { ...mocks, 'npm-profile': npmProfile, }) + const profile = new Profile(npm) t.test('default output', t => { - profile(['get'], err => { + profile.exec(['get'], err => { if (err) throw err @@ -109,7 +110,7 @@ t.test('profile get no args', t => { t.test('--json', t => { npm.flatOptions.json = true - profile(['get'], err => { + profile.exec(['get'], err => { if (err) throw err @@ -125,7 +126,7 @@ t.test('profile get no args', t => { t.test('--parseable', t => { npm.flatOptions.parseable = true - profile(['get'], err => { + profile.exec(['get'], err => { if (err) throw err @@ -147,12 +148,13 @@ t.test('profile get no args', t => { }, } - const profile = requireInject('../../lib/profile.js', { + const Profile = requireInject('../../lib/profile.js', { ...mocks, 'npm-profile': npmProfile, }) + const profile = new Profile(npm) - profile(['get'], err => { + profile.exec(['get'], err => { if (err) throw err @@ -174,12 +176,13 @@ t.test('profile get no args', t => { }, } - const profile = requireInject('../../lib/profile.js', { + const Profile = requireInject('../../lib/profile.js', { ...mocks, 'npm-profile': npmProfile, }) + const profile = new Profile(npm) - profile(['get'], err => { + profile.exec(['get'], err => { if (err) throw err @@ -201,12 +204,13 @@ t.test('profile get no args', t => { }, } - const profile = requireInject('../../lib/profile.js', { + const Profile = requireInject('../../lib/profile.js', { ...mocks, 'npm-profile': npmProfile, }) + const profile = new Profile(npm) - profile(['get'], err => { + profile.exec(['get'], err => { if (err) throw err @@ -228,13 +232,14 @@ t.test('profile get <key>', t => { }, } - const profile = requireInject('../../lib/profile.js', { + const Profile = requireInject('../../lib/profile.js', { ...mocks, 'npm-profile': npmProfile, }) + const profile = new Profile(npm) t.test('default output', t => { - profile(['get', 'name'], err => { + profile.exec(['get', 'name'], err => { if (err) throw err @@ -250,7 +255,7 @@ t.test('profile get <key>', t => { t.test('--json', t => { npm.flatOptions.json = true - profile(['get', 'name'], err => { + profile.exec(['get', 'name'], err => { if (err) throw err @@ -266,7 +271,7 @@ t.test('profile get <key>', t => { t.test('--parseable', t => { npm.flatOptions.parseable = true - profile(['get', 'name'], err => { + profile.exec(['get', 'name'], err => { if (err) throw err @@ -288,13 +293,14 @@ t.test('profile get multiple args', t => { }, } - const profile = requireInject('../../lib/profile.js', { + const Profile = requireInject('../../lib/profile.js', { ...mocks, 'npm-profile': npmProfile, }) + const profile = new Profile(npm) t.test('default output', t => { - profile(['get', 'name', 'email', 'github'], err => { + profile.exec(['get', 'name', 'email', 'github'], err => { if (err) throw err @@ -309,7 +315,7 @@ t.test('profile get multiple args', t => { t.test('--json', t => { npm.flatOptions.json = true - profile(['get', 'name', 'email', 'github'], err => { + profile.exec(['get', 'name', 'email', 'github'], err => { if (err) throw err @@ -325,7 +331,7 @@ t.test('profile get multiple args', t => { t.test('--parseable', t => { npm.flatOptions.parseable = true - profile(['get', 'name', 'email', 'github'], err => { + profile.exec(['get', 'name', 'email', 'github'], err => { if (err) throw err @@ -338,7 +344,7 @@ t.test('profile get multiple args', t => { }) t.test('comma separated', t => { - profile(['get', 'name,email,github'], err => { + profile.exec(['get', 'name,email,github'], err => { if (err) throw err @@ -374,7 +380,7 @@ t.test('profile set <key> <value>', t => { }) t.test('no key', t => { - profile(['set'], err => { + profile.exec(['set'], err => { t.match( err, /npm profile set <prop> <value>/, @@ -385,7 +391,7 @@ t.test('profile set <key> <value>', t => { }) t.test('no value', t => { - profile(['set', 'email'], err => { + profile.exec(['set', 'email'], err => { t.match( err, /npm profile set <prop> <value>/, @@ -396,7 +402,7 @@ t.test('profile set <key> <value>', t => { }) t.test('set password', t => { - profile(['set', 'password', '1234'], err => { + profile.exec(['set', 'password', '1234'], err => { t.match( err, /Do not include your current or new passwords on the command line./, @@ -407,7 +413,7 @@ t.test('profile set <key> <value>', t => { }) t.test('unwritable key', t => { - profile(['set', 'name', 'foo'], err => { + profile.exec(['set', 'name', 'foo'], err => { t.match( err, /"name" is not a property we can set./, @@ -421,12 +427,13 @@ t.test('profile set <key> <value>', t => { t.test('default output', t => { t.plan(2) - const profile = requireInject('../../lib/profile.js', { + const Profile = requireInject('../../lib/profile.js', { ...mocks, 'npm-profile': npmProfile(t), }) + const profile = new Profile(npm) - profile(['set', 'fullname', 'Lorem Ipsum'], err => { + profile.exec(['set', 'fullname', 'Lorem Ipsum'], err => { if (err) throw err @@ -443,12 +450,13 @@ t.test('profile set <key> <value>', t => { npm.flatOptions.json = true - const profile = requireInject('../../lib/profile.js', { + const Profile = requireInject('../../lib/profile.js', { ...mocks, 'npm-profile': npmProfile(t), }) + const profile = new Profile(npm) - profile(['set', 'fullname', 'Lorem Ipsum'], err => { + profile.exec(['set', 'fullname', 'Lorem Ipsum'], err => { if (err) throw err @@ -467,12 +475,13 @@ t.test('profile set <key> <value>', t => { npm.flatOptions.parseable = true - const profile = requireInject('../../lib/profile.js', { + const Profile = requireInject('../../lib/profile.js', { ...mocks, 'npm-profile': npmProfile(t), }) + const profile = new Profile(npm) - profile(['set', 'fullname', 'Lorem Ipsum'], err => { + profile.exec(['set', 'fullname', 'Lorem Ipsum'], err => { if (err) throw err @@ -513,12 +522,13 @@ t.test('profile set <key> <value>', t => { }, } - const profile = requireInject('../../lib/profile.js', { + const Profile = requireInject('../../lib/profile.js', { ...mocks, 'npm-profile': npmProfile, }) + const profile = new Profile(npm) - profile(['set', 'email', 'foo@npmjs.com'], err => { + profile.exec(['set', 'email', 'foo@npmjs.com'], err => { if (err) throw err @@ -576,13 +586,14 @@ t.test('profile set <key> <value>', t => { }, } - const profile = requireInject('../../lib/profile.js', { + const Profile = requireInject('../../lib/profile.js', { ...mocks, 'npm-profile': npmProfile, '../../lib/utils/read-user-info.js': readUserInfo, }) + const profile = new Profile(npm) - profile(['set', 'password'], err => { + profile.exec(['set', 'password'], err => { if (err) throw err @@ -643,14 +654,15 @@ t.test('profile set <key> <value>', t => { }, } - const profile = requireInject('../../lib/profile.js', { + const Profile = requireInject('../../lib/profile.js', { ...mocks, npmlog, 'npm-profile': npmProfile, '../../lib/utils/read-user-info.js': readUserInfo, }) + const profile = new Profile(npm) - profile(['set', 'password'], err => { + profile.exec(['set', 'password'], err => { if (err) throw err @@ -668,7 +680,7 @@ t.test('profile set <key> <value>', t => { t.test('enable-2fa', t => { t.test('invalid args', t => { - profile(['enable-2fa', 'foo', 'bar'], err => { + profile.exec(['enable-2fa', 'foo', 'bar'], err => { t.match( err, /npm profile enable-2fa \[auth-and-writes|auth-only\]/, @@ -679,7 +691,7 @@ t.test('enable-2fa', t => { }) t.test('invalid two factor auth mode', t => { - profile(['enable-2fa', 'foo'], err => { + profile.exec(['enable-2fa', 'foo'], err => { t.match( err, /Invalid two-factor authentication mode "foo"/, @@ -692,7 +704,7 @@ t.test('enable-2fa', t => { t.test('no support for --json output', t => { npm.flatOptions.json = true - profile(['enable-2fa', 'auth-only'], err => { + profile.exec(['enable-2fa', 'auth-only'], err => { t.match( err.message, 'Enabling two-factor authentication is an interactive ' + @@ -706,7 +718,7 @@ t.test('enable-2fa', t => { t.test('no support for --parseable output', t => { npm.flatOptions.parseable = true - profile(['enable-2fa', 'auth-only'], err => { + profile.exec(['enable-2fa', 'auth-only'], err => { t.match( err.message, 'Enabling two-factor authentication is an interactive ' + @@ -733,12 +745,13 @@ t.test('enable-2fa', t => { }, } - const profile = requireInject('../../lib/profile.js', { + const Profile = requireInject('../../lib/profile.js', { ...mocks, 'npm-profile': npmProfile, }) + const profile = new Profile(npm) - profile(['enable-2fa', 'auth-only'], err => { + profile.exec(['enable-2fa', 'auth-only'], err => { t.match( err.message, 'Your registry https://registry.npmjs.org/ does ' + @@ -761,12 +774,13 @@ t.test('enable-2fa', t => { }, } - const profile = requireInject('../../lib/profile.js', { + const Profile = requireInject('../../lib/profile.js', { ...mocks, 'npm-profile': npmProfile, }) + const profile = new Profile(npm) - profile(['enable-2fa', 'auth-only'], err => { + profile.exec(['enable-2fa', 'auth-only'], err => { t.match( err.message, 'Your registry https://registry.npmjs.org/ does ' + @@ -781,11 +795,12 @@ t.test('enable-2fa', t => { t.test('no auth found', t => { npm.config.getCredentialsByURI = () => ({}) - const profile = requireInject('../../lib/profile.js', { + const Profile = requireInject('../../lib/profile.js', { ...mocks, }) + const profile = new Profile(npm) - profile(['enable-2fa', 'auth-only'], err => { + profile.exec(['enable-2fa', 'auth-only'], err => { t.match( err.message, 'You need to be logged in to registry ' + @@ -861,13 +876,14 @@ t.test('enable-2fa', t => { }, } - const profile = requireInject('../../lib/profile.js', { + const Profile = requireInject('../../lib/profile.js', { ...mocks, 'npm-profile': npmProfile, '../../lib/utils/read-user-info.js': readUserInfo, }) + const profile = new Profile(npm) - profile(['enable-2fa', 'auth-only'], err => { + profile.exec(['enable-2fa', 'auth-only'], err => { if (err) throw err @@ -964,14 +980,15 @@ t.test('enable-2fa', t => { generate: (url, cb) => cb('qrcode'), } - const profile = requireInject('../../lib/profile.js', { + const Profile = requireInject('../../lib/profile.js', { ...mocks, 'npm-profile': npmProfile, 'qrcode-terminal': qrcode, '../../lib/utils/read-user-info.js': readUserInfo, }) + const profile = new Profile(npm) - profile(['enable-2fa', 'auth-only'], err => { + profile.exec(['enable-2fa', 'auth-only'], err => { if (err) throw err @@ -1017,13 +1034,14 @@ t.test('enable-2fa', t => { }, } - const profile = requireInject('../../lib/profile.js', { + const Profile = requireInject('../../lib/profile.js', { ...mocks, 'npm-profile': npmProfile, '../../lib/utils/read-user-info.js': readUserInfo, }) + const profile = new Profile(npm) - profile(['enable-2fa', 'auth-only'], err => { + profile.exec(['enable-2fa', 'auth-only'], err => { t.match( err, /Unknown error enabling two-factor authentication./, @@ -1063,13 +1081,14 @@ t.test('enable-2fa', t => { }, } - const profile = requireInject('../../lib/profile.js', { + const Profile = requireInject('../../lib/profile.js', { ...mocks, 'npm-profile': npmProfile, '../../lib/utils/read-user-info.js': readUserInfo, }) + const profile = new Profile(npm) - profile(['enable-2fa', 'auth-and-writes'], err => { + profile.exec(['enable-2fa', 'auth-and-writes'], err => { if (err) throw err @@ -1113,13 +1132,14 @@ t.test('enable-2fa', t => { }, } - const profile = requireInject('../../lib/profile.js', { + const Profile = requireInject('../../lib/profile.js', { ...mocks, 'npm-profile': npmProfile, '../../lib/utils/read-user-info.js': readUserInfo, }) + const profile = new Profile(npm) - profile(['enable-2fa', 'auth-only'], err => { + profile.exec(['enable-2fa', 'auth-only'], err => { if (err) throw err @@ -1163,13 +1183,14 @@ t.test('enable-2fa', t => { }, } - const profile = requireInject('../../lib/profile.js', { + const Profile = requireInject('../../lib/profile.js', { ...mocks, 'npm-profile': npmProfile, '../../lib/utils/read-user-info.js': readUserInfo, }) + const profile = new Profile(npm) - profile(['enable-2fa'], err => { + profile.exec(['enable-2fa'], err => { if (err) throw err @@ -1196,12 +1217,13 @@ t.test('disable-2fa', t => { }, } - const profile = requireInject('../../lib/profile.js', { + const Profile = requireInject('../../lib/profile.js', { ...mocks, 'npm-profile': npmProfile, }) + const profile = new Profile(npm) - profile(['disable-2fa'], err => { + profile.exec(['disable-2fa'], err => { if (err) throw err @@ -1257,13 +1279,14 @@ t.test('disable-2fa', t => { }) t.test('default output', t => { - const profile = requireInject('../../lib/profile.js', { + const Profile = requireInject('../../lib/profile.js', { ...mocks, 'npm-profile': npmProfile(t), '../../lib/utils/read-user-info.js': readUserInfo(t), }) + const profile = new Profile(npm) - profile(['disable-2fa'], err => { + profile.exec(['disable-2fa'], err => { if (err) throw err @@ -1279,13 +1302,14 @@ t.test('disable-2fa', t => { t.test('--json', t => { npm.flatOptions.json = true - const profile = requireInject('../../lib/profile.js', { + const Profile = requireInject('../../lib/profile.js', { ...mocks, 'npm-profile': npmProfile(t), '../../lib/utils/read-user-info.js': readUserInfo(t), }) + const profile = new Profile(npm) - profile(['disable-2fa'], err => { + profile.exec(['disable-2fa'], err => { if (err) throw err @@ -1301,13 +1325,14 @@ t.test('disable-2fa', t => { t.test('--parseable', t => { npm.flatOptions.parseable = true - const profile = requireInject('../../lib/profile.js', { + const Profile = requireInject('../../lib/profile.js', { ...mocks, 'npm-profile': npmProfile(t), '../../lib/utils/read-user-info.js': readUserInfo(t), }) + const profile = new Profile(npm) - profile(['disable-2fa'], err => { + profile.exec(['disable-2fa'], err => { if (err) throw err @@ -1363,13 +1388,14 @@ t.test('disable-2fa', t => { }, } - const profile = requireInject('../../lib/profile.js', { + const Profile = requireInject('../../lib/profile.js', { ...mocks, 'npm-profile': npmProfile, '../../lib/utils/read-user-info.js': readUserInfo, }) + const profile = new Profile(npm) - profile(['disable-2fa'], err => { + profile.exec(['disable-2fa'], err => { if (err) throw err @@ -1385,7 +1411,7 @@ t.test('disable-2fa', t => { }) t.test('unknown subcommand', t => { - profile(['asfd'], err => { + profile.exec(['asfd'], err => { t.match( err, /Unknown profile command: asfd/, @@ -1396,11 +1422,9 @@ t.test('unknown subcommand', t => { }) t.test('completion', t => { - const { completion } = profile - const testComp = async ({ t, argv, expect, title }) => { t.resolveMatch( - completion({ conf: { argv: { remain: argv } } }), + profile.completion({ conf: { argv: { remain: argv } } }), expect, title ) @@ -1444,7 +1468,7 @@ t.test('completion', t => { t.test('npm profile unknown subcommand autocomplete', async t => { t.rejects( - completion({ conf: { argv: { remain: ['npm', 'profile', 'asdf'] } } }), + profile.completion({ conf: { argv: { remain: ['npm', 'profile', 'asdf'] } } }), { message: 'asdf not recognized' }, 'should throw unknown cmd error' ) t.end() diff --git a/test/lib/prune.js b/test/lib/prune.js index 074f4eac6..8cd148806 100644 --- a/test/lib/prune.js +++ b/test/lib/prune.js @@ -2,13 +2,7 @@ const { test } = require('tap') const requireInject = require('require-inject') test('should prune using Arborist', (t) => { - const prune = requireInject('../../lib/prune.js', { - '../../lib/npm.js': { - prefix: 'foo', - flatOptions: { - foo: 'bar', - }, - }, + const Prune = requireInject('../../lib/prune.js', { '@npmcli/arborist': function (args) { t.ok(args, 'gets options object') t.ok(args.path, 'gets path option') @@ -20,7 +14,13 @@ test('should prune using Arborist', (t) => { t.ok(arb, 'gets arborist tree') }, }) - prune(null, er => { + const prune = new Prune({ + prefix: 'foo', + flatOptions: { + foo: 'bar', + }, + }) + prune.exec(null, er => { if (er) throw er t.ok(true, 'callback is called') diff --git a/test/lib/publish.js b/test/lib/publish.js index 5243b5254..0e857fafd 100644 --- a/test/lib/publish.js +++ b/test/lib/publish.js @@ -34,19 +34,7 @@ t.test('should publish with libnpmpublish, passing through flatOptions and respe }, null, 2), }) - const publish = requireInject('../../lib/publish.js', { - '../../lib/npm.js': { - flatOptions: { - customValue: true, - }, - config: { - ...config, - getCredentialsByURI: (uri) => { - t.same(uri, registry, 'gets credentials for expected registry') - return { token: 'some.registry.token' } - }, - }, - }, + const Publish = requireInject('../../lib/publish.js', { // verify that we do NOT remove publishConfig if it was there originally // and then removed during the script/pack process libnpmpack: async () => { @@ -66,11 +54,24 @@ t.test('should publish with libnpmpublish, passing through flatOptions and respe }, }, }) + const publish = new Publish({ + flatOptions: { + customValue: true, + }, + config: { + ...config, + getCredentialsByURI: (uri) => { + t.same(uri, registry, 'gets credentials for expected registry') + return { token: 'some.registry.token' } + }, + }, + }) - return publish([testDir], (er) => { + publish.exec([testDir], (er) => { if (er) throw er t.pass('got to callback') + t.end() }) }) @@ -85,16 +86,7 @@ t.test('re-loads publishConfig.registry if added during script process', (t) => }, null, 2), }) - const publish = requireInject('../../lib/publish.js', { - '../../lib/npm.js': { - config: { - ...config, - getCredentialsByURI: (uri) => { - t.same(uri, registry, 'gets credentials for expected registry') - return { token: 'some.registry.token' } - }, - }, - }, + const Publish = requireInject('../../lib/publish.js', { libnpmpack: async () => { fs.writeFileSync(`${testDir}/package.json`, JSON.stringify({ name: 'my-cool-pkg', @@ -112,11 +104,21 @@ t.test('re-loads publishConfig.registry if added during script process', (t) => }, }, }) + const publish = new Publish({ + config: { + ...config, + getCredentialsByURI: (uri) => { + t.same(uri, registry, 'gets credentials for expected registry') + return { token: 'some.registry.token' } + }, + }, + }) - return publish([testDir], (er) => { + publish.exec([testDir], (er) => { if (er) throw er t.pass('got to callback') + t.end() }) }) @@ -131,19 +133,7 @@ t.test('if loglevel=info and json, should not output package contents', (t) => { }) log.level = 'info' - const publish = requireInject('../../lib/publish.js', { - '../../lib/npm.js': { - flatOptions: { - json: true, - }, - config: { - ...config, - getCredentialsByURI: (uri) => { - t.same(uri, defaults.registry, 'gets credentials for expected registry') - return { token: 'some.registry.token' } - }, - }, - }, + const Publish = requireInject('../../lib/publish.js', { '../../lib/utils/output.js': () => { t.pass('output is called') }, @@ -161,11 +151,24 @@ t.test('if loglevel=info and json, should not output package contents', (t) => { }, }, }) + const publish = new Publish({ + flatOptions: { + json: true, + }, + config: { + ...config, + getCredentialsByURI: (uri) => { + t.same(uri, defaults.registry, 'gets credentials for expected registry') + return { token: 'some.registry.token' } + }, + }, + }) - return publish([testDir], (er) => { + publish.exec([testDir], (er) => { if (er) throw er t.pass('got to callback') + t.end() }) }) @@ -180,18 +183,7 @@ t.test('if loglevel=silent and dry-run, should not output package contents or pu }) log.level = 'silent' - const publish = requireInject('../../lib/publish.js', { - '../../lib/npm.js': { - flatOptions: { - dryRun: true, - }, - config: { - ...config, - getCredentialsByURI: () => { - throw new Error('should not call getCredentialsByURI in dry run') - }, - }, - }, + const Publish = requireInject('../../lib/publish.js', { '../../lib/utils/output.js': () => { throw new Error('should not output in dry run mode') }, @@ -209,11 +201,23 @@ t.test('if loglevel=silent and dry-run, should not output package contents or pu }, }, }) + const publish = new Publish({ + flatOptions: { + dryRun: true, + }, + config: { + ...config, + getCredentialsByURI: () => { + throw new Error('should not call getCredentialsByURI in dry run') + }, + }, + }) - return publish([testDir], (er) => { + publish.exec([testDir], (er) => { if (er) throw er t.pass('got to callback') + t.end() }) }) @@ -228,17 +232,7 @@ t.test('if loglevel=info and dry-run, should not publish, should log package con }) log.level = 'info' - const publish = requireInject('../../lib/publish.js', { - '../../lib/npm.js': { - flatOptions: { - dryRun: true, - }, - config: { - ...config, - getCredentialsByURI: () => { - throw new Error('should not call getCredentialsByURI in dry run') - }}, - }, + const Publish = requireInject('../../lib/publish.js', { '../../lib/utils/tar.js': { getContents: () => ({ id: 'someid', @@ -256,37 +250,52 @@ t.test('if loglevel=info and dry-run, should not publish, should log package con }, }, }) + const publish = new Publish({ + flatOptions: { + dryRun: true, + }, + config: { + ...config, + getCredentialsByURI: () => { + throw new Error('should not call getCredentialsByURI in dry run') + }}, + }) - return publish([testDir], (er) => { + publish.exec([testDir], (er) => { if (er) throw er t.pass('got to callback') + t.end() }) }) t.test('shows usage with wrong set of arguments', (t) => { t.plan(1) - const publish = requireInject('../../lib/publish.js') + const Publish = requireInject('../../lib/publish.js') + const publish = new Publish({}) - return publish(['a', 'b', 'c'], (er) => t.matchSnapshot(er, 'should print usage')) + publish.exec(['a', 'b', 'c'], (er) => { + t.matchSnapshot(er, 'should print usage') + t.end() + }) }) t.test('throws when invalid tag', (t) => { t.plan(1) - const publish = requireInject('../../lib/publish.js', { - '../../lib/npm.js': { - flatOptions: { - defaultTag: '0.0.13', - }, - config, + const Publish = requireInject('../../lib/publish.js') + const publish = new Publish({ + flatOptions: { + defaultTag: '0.0.13', }, + config, }) - return publish([], (err) => { + publish.exec([], (err) => { t.match(err, { message: /Tag name must not be a valid SemVer range: /, }, 'throws when tag name is a valid SemVer range') + t.end() }) }) @@ -310,16 +319,7 @@ t.test('can publish a tarball', t => { }, ['package']) const tarFile = fs.readFileSync(`${testDir}/tarball/package.tgz`) - const publish = requireInject('../../lib/publish.js', { - '../../lib/npm.js': { - config: { - ...config, - getCredentialsByURI: (uri) => { - t.same(uri, defaults.registry, 'gets credentials for expected registry') - return { token: 'some.registry.token' } - }, - }, - }, + const Publish = requireInject('../../lib/publish.js', { libnpmpublish: { publish: (manifest, tarData, opts) => { t.match(manifest, { @@ -330,63 +330,73 @@ t.test('can publish a tarball', t => { }, }, }) + const publish = new Publish({ + config: { + ...config, + getCredentialsByURI: (uri) => { + t.same(uri, defaults.registry, 'gets credentials for expected registry') + return { token: 'some.registry.token' } + }, + }, + }) - return publish([`${testDir}/tarball/package.tgz`], (er) => { + publish.exec([`${testDir}/tarball/package.tgz`], (er) => { if (er) throw er t.pass('got to callback') + t.end() }) }) -t.test('should check auth for default registry', async t => { +t.test('should check auth for default registry', t => { t.plan(2) - const publish = requireInject('../../lib/publish.js', { - '../../lib/npm.js': { - config: { - ...config, - getCredentialsByURI: (uri) => { - t.same(uri, defaults.registry, 'gets credentials for expected registry') - return {} - }, + const Publish = requireInject('../../lib/publish.js') + const publish = new Publish({ + config: { + ...config, + getCredentialsByURI: (uri) => { + t.same(uri, defaults.registry, 'gets credentials for expected registry') + return {} }, }, }) - return publish([], (err) => { + publish.exec([], (err) => { t.match(err, { message: 'This command requires you to be logged in.', code: 'ENEEDAUTH', }, 'throws when not logged in') + t.end() }) }) -t.test('should check auth for configured registry', async t => { +t.test('should check auth for configured registry', t => { t.plan(2) const registry = 'https://some.registry' - const publish = requireInject('../../lib/publish.js', { - '../../lib/npm.js': { - flatOptions: { - registry, - }, - config: { - ...config, - getCredentialsByURI: (uri) => { - t.same(uri, registry, 'gets credentials for expected registry') - return {} - }, + const Publish = requireInject('../../lib/publish.js') + const publish = new Publish({ + flatOptions: { + registry, + }, + config: { + ...config, + getCredentialsByURI: (uri) => { + t.same(uri, registry, 'gets credentials for expected registry') + return {} }, }, }) - return publish([], (err) => { + publish.exec([], (err) => { t.match(err, { message: 'This command requires you to be logged in.', code: 'ENEEDAUTH', }, 'throws when not logged in') + t.end() }) }) -t.test('should check auth for scope specific registry', async t => { +t.test('should check auth for scope specific registry', t => { t.plan(2) const registry = 'https://some.registry' const testDir = t.testdir({ @@ -396,26 +406,26 @@ t.test('should check auth for scope specific registry', async t => { }, null, 2), }) - const publish = requireInject('../../lib/publish.js', { - '../../lib/npm.js': { - flatOptions: { - '@npm:registry': registry, - }, - config: { - ...config, - getCredentialsByURI: (uri) => { - t.same(uri, registry, 'gets credentials for expected registry') - return {} - }, + const Publish = requireInject('../../lib/publish.js') + const publish = new Publish({ + flatOptions: { + '@npm:registry': registry, + }, + config: { + ...config, + getCredentialsByURI: (uri) => { + t.same(uri, registry, 'gets credentials for expected registry') + return {} }, }, }) - return publish([testDir], (err) => { + publish.exec([testDir], (err) => { t.match(err, { message: 'This command requires you to be logged in.', code: 'ENEEDAUTH', }, 'throws when not logged in') + t.end() }) }) @@ -429,19 +439,7 @@ t.test('should use auth for scope specific registry', t => { }, null, 2), }) - const publish = requireInject('../../lib/publish.js', { - '../../lib/npm.js': { - flatOptions: { - '@npm:registry': registry, - }, - config: { - ...config, - getCredentialsByURI: (uri) => { - t.same(uri, registry, 'gets credentials for expected registry') - return { token: 'some.registry.token' } - }, - }, - }, + const Publish = requireInject('../../lib/publish.js', { libnpmpublish: { publish: (manifest, tarData, opts) => { t.ok(opts, 'gets opts object') @@ -449,10 +447,23 @@ t.test('should use auth for scope specific registry', t => { }, }, }) - return publish([testDir], (er) => { + const publish = new Publish({ + flatOptions: { + '@npm:registry': registry, + }, + config: { + ...config, + getCredentialsByURI: (uri) => { + t.same(uri, registry, 'gets credentials for expected registry') + return { token: 'some.registry.token' } + }, + }, + }) + publish.exec([testDir], (er) => { if (er) throw er t.pass('got to callback') + t.end() }) }) @@ -469,16 +480,7 @@ t.test('read registry only from publishConfig', t => { }, null, 2), }) - const publish = requireInject('../../lib/publish.js', { - '../../lib/npm.js': { - config: { - ...config, - getCredentialsByURI: (uri) => { - t.same(uri, registry, 'gets credentials for expected registry') - return { token: 'some.registry.token' } - }, - }, - }, + const Publish = requireInject('../../lib/publish.js', { libnpmpublish: { publish: (manifest, tarData, opts) => { t.match(manifest, { name: 'my-cool-pkg', version: '1.0.0' }, 'gets manifest') @@ -486,10 +488,20 @@ t.test('read registry only from publishConfig', t => { }, }, }) + const publish = new Publish({ + config: { + ...config, + getCredentialsByURI: (uri) => { + t.same(uri, registry, 'gets credentials for expected registry') + return { token: 'some.registry.token' } + }, + }, + }) - return publish([testDir], (er) => { + publish.exec([testDir], (er) => { if (er) throw er t.pass('got to callback') + t.end() }) }) diff --git a/test/lib/rebuild.js b/test/lib/rebuild.js index d9df048d9..ee081c087 100644 --- a/test/lib/rebuild.js +++ b/test/lib/rebuild.js @@ -13,14 +13,14 @@ const npm = { prefix: '', } const mocks = { - '../../lib/npm.js': npm, '../../lib/utils/output.js': (...msg) => { result += msg.join('\n') }, '../../lib/utils/usage.js': () => 'usage instructions', } -const rebuild = requireInject('../../lib/rebuild.js', mocks) +const Rebuild = requireInject('../../lib/rebuild.js', mocks) +const rebuild = new Rebuild(npm) t.afterEach(cb => { npm.prefix = '' @@ -67,7 +67,7 @@ t.test('no args', t => { npm.prefix = path - rebuild([], err => { + rebuild.exec([], err => { if (err) throw err @@ -115,7 +115,7 @@ t.test('filter by pkg name', t => { t.throws(() => fs.statSync(aBinFile)) t.throws(() => fs.statSync(bBinFile)) - rebuild(['b'], err => { + rebuild.exec(['b'], err => { if (err) throw err @@ -163,7 +163,7 @@ t.test('filter by pkg@<range>', t => { const bBinFile = resolve(path, 'node_modules/.bin/b') const nestedBinFile = resolve(path, 'node_modules/a/node_modules/.bin/b') - rebuild(['b@2'], err => { + rebuild.exec(['b@2'], err => { if (err) throw err @@ -203,7 +203,7 @@ t.test('filter by directory', t => { t.throws(() => fs.statSync(aBinFile)) t.throws(() => fs.statSync(bBinFile)) - rebuild(['file:node_modules/b'], err => { + rebuild.exec(['file:node_modules/b'], err => { if (err) throw err @@ -215,7 +215,7 @@ t.test('filter by directory', t => { }) t.test('filter must be a semver version/range, or directory', t => { - rebuild(['git+ssh://github.com/npm/arborist'], err => { + rebuild.exec(['git+ssh://github.com/npm/arborist'], err => { t.match( err, /Error: `npm rebuild` only supports SemVer version\/range specifiers/, @@ -245,7 +245,7 @@ t.test('global prefix', t => { npm.flatOptions.global = true npm.globalDir = resolve(globalPath, 'lib', 'node_modules') - rebuild([], err => { + rebuild.exec([], err => { if (err) throw err diff --git a/test/lib/repo.js b/test/lib/repo.js index 3367f7c88..7abda55ca 100644 --- a/test/lib/repo.js +++ b/test/lib/repo.js @@ -108,16 +108,17 @@ const pacote = { // keep a tally of which urls got opened const opened = {} -const openUrl = (url, errMsg, cb) => { +const openUrl = async (npm, url, errMsg, cb) => { opened[url] = opened[url] || 0 opened[url]++ process.nextTick(cb) } -const repo = requireInject('../../lib/repo.js', { +const Repo = requireInject('../../lib/repo.js', { pacote, '../../lib/utils/open-url.js': openUrl, }) +const repo = new Repo({ flatOptions: {} }) t.test('open repo urls', t => { const expect = { @@ -150,7 +151,7 @@ t.test('open repo urls', t => { t.plan(keys.length) keys.forEach(pkg => { t.test(pkg, t => { - repo([pkg], (er) => { + repo.exec([pkg], (er) => { if (er) throw er const url = expect[pkg] @@ -173,7 +174,7 @@ t.test('fail if cannot figure out repo url', t => { cases.forEach(pkg => { t.test(pkg, t => { - repo([pkg], er => { + repo.exec([pkg], er => { t.match(er, { pkgid: pkg }) t.end() }) @@ -182,7 +183,7 @@ t.test('fail if cannot figure out repo url', t => { }) t.test('open default package if none specified', t => { - repo([], (er) => { + repo.exec([], (er) => { if (er) throw er t.equal(opened['https://example.com/thispkg'], 2, 'opened expected url', {opened}) diff --git a/test/lib/restart.js b/test/lib/restart.js index a19bfd0d4..f29592d9b 100644 --- a/test/lib/restart.js +++ b/test/lib/restart.js @@ -1,4 +1,17 @@ const t = require('tap') -const restart = require('../../lib/restart.js') -t.isa(restart, Function) +let runArgs +const npm = { + commands: { + 'run-script': (args, cb) => { + runArgs = args + cb() + }, + }, +} +const Restart = require('../../lib/restart.js') +const restart = new Restart(npm) t.equal(restart.usage, 'npm restart [-- <args>]') +restart.exec(['foo'], () => { + t.match(runArgs, ['restart', 'foo']) + t.end() +}) diff --git a/test/lib/root.js b/test/lib/root.js index 8c23152b3..e8ccc1106 100644 --- a/test/lib/root.js +++ b/test/lib/root.js @@ -5,14 +5,14 @@ test('root', (t) => { t.plan(3) const dir = '/root/dir' - const root = requireInject('../../lib/root.js', { - '../../lib/npm.js': { dir }, + const Root = requireInject('../../lib/root.js', { '../../lib/utils/output.js': (output) => { t.equal(output, dir, 'prints the correct directory') }, }) + const root = new Root({ dir }) - root([], (err) => { + root.exec([], (err) => { t.ifError(err, 'npm root') t.ok('should have printed directory') }) diff --git a/test/lib/run-script.js b/test/lib/run-script.js index 974202aa8..43592d324 100644 --- a/test/lib/run-script.js +++ b/test/lib/run-script.js @@ -22,19 +22,29 @@ const npm = { const output = [] -const npmlog = { level: 'warn' } -const getRS = windows => requireInject('../../lib/run-script.js', { - '@npmcli/run-script': Object.assign(async opts => { - RUN_SCRIPTS.push(opts) - }, { - isServerPackage: require('@npmcli/run-script').isServerPackage, - }), - npmlog, - '../../lib/npm.js': npm, - '../../lib/utils/is-windows-shell.js': windows, - '../../lib/utils/output.js': (...msg) => output.push(msg), +t.afterEach(cb => { + output.length = 0 + RUN_SCRIPTS.length = 0 + npm.flatOptions.json = false + npm.flatOptions.parseable = false + cb() }) +const npmlog = { level: 'warn' } +const getRS = windows => { + const RunScript = requireInject('../../lib/run-script.js', { + '@npmcli/run-script': Object.assign(async opts => { + RUN_SCRIPTS.push(opts) + }, { + isServerPackage: require('@npmcli/run-script').isServerPackage, + }), + npmlog, + '../../lib/utils/is-windows-shell.js': windows, + '../../lib/utils/output.js': (...msg) => output.push(msg), + }) + return new RunScript(npm) +} + const runScript = getRS(false) const runScriptWin = getRS(true) @@ -69,109 +79,119 @@ t.test('completion', t => { t.end() }) -t.test('fail if no package.json', async t => { +t.test('fail if no package.json', t => { + t.plan(2) npm.localPrefix = t.testdir() - await runScript([], er => t.match(er, { code: 'ENOENT' })) - await runScript(['test'], er => t.match(er, { code: 'ENOENT' })) + runScript.exec([], er => t.match(er, { code: 'ENOENT' })) + runScript.exec(['test'], er => t.match(er, { code: 'ENOENT' })) }) -t.test('default env, start, and restart scripts', async t => { +t.test('default env, start, and restart scripts', t => { npm.localPrefix = t.testdir({ 'package.json': JSON.stringify({ name: 'x', version: '1.2.3' }), 'server.js': 'console.log("hello, world")', }) - await runScript(['start'], er => { - if (er) - throw er + t.test('start', t => { + runScript.exec(['start'], er => { + if (er) + throw er - t.match(RUN_SCRIPTS, [ - { - path: npm.localPrefix, - args: [], - scriptShell: undefined, - stdio: 'inherit', - stdioString: true, - pkg: { name: 'x', version: '1.2.3', _id: 'x@1.2.3', scripts: {}}, - event: 'start', - }, - ]) + t.match(RUN_SCRIPTS, [ + { + path: npm.localPrefix, + args: [], + scriptShell: undefined, + stdio: 'inherit', + stdioString: true, + pkg: { name: 'x', version: '1.2.3', _id: 'x@1.2.3', scripts: {}}, + event: 'start', + }, + ]) + t.end() + }) }) - RUN_SCRIPTS.length = 0 - await runScript(['env'], er => { - if (er) - throw er + t.test('env', t => { + runScript.exec(['env'], er => { + if (er) + throw er - t.match(RUN_SCRIPTS, [ - { - path: npm.localPrefix, - args: [], - scriptShell: undefined, - stdio: 'inherit', - stdioString: true, - pkg: { - name: 'x', - version: '1.2.3', - _id: 'x@1.2.3', - scripts: { - env: 'env', + t.match(RUN_SCRIPTS, [ + { + path: npm.localPrefix, + args: [], + scriptShell: undefined, + stdio: 'inherit', + stdioString: true, + pkg: { + name: 'x', + version: '1.2.3', + _id: 'x@1.2.3', + scripts: { + env: 'env', + }, }, + event: 'env', }, - event: 'env', - }, - ]) + ]) + t.end() + }) }) - RUN_SCRIPTS.length = 0 - await runScriptWin(['env'], er => { - if (er) - throw er + t.test('windows env', t => { + runScriptWin.exec(['env'], er => { + if (er) + throw er - t.match(RUN_SCRIPTS, [ - { - path: npm.localPrefix, - args: [], - scriptShell: undefined, - stdio: 'inherit', - stdioString: true, - pkg: { name: 'x', - version: '1.2.3', - _id: 'x@1.2.3', - scripts: { - env: 'SET', - } }, - event: 'env', - }, - ]) + t.match(RUN_SCRIPTS, [ + { + path: npm.localPrefix, + args: [], + scriptShell: undefined, + stdio: 'inherit', + stdioString: true, + pkg: { name: 'x', + version: '1.2.3', + _id: 'x@1.2.3', + scripts: { + env: 'SET', + } }, + event: 'env', + }, + ]) + t.end() + }) }) - RUN_SCRIPTS.length = 0 - await runScript(['restart'], er => { - if (er) - throw er + t.test('restart', t => { + runScript.exec(['restart'], er => { + if (er) + throw er - t.match(RUN_SCRIPTS, [ - { - path: npm.localPrefix, - args: [], - scriptShell: undefined, - stdio: 'inherit', - stdioString: true, - pkg: { name: 'x', - version: '1.2.3', - _id: 'x@1.2.3', - scripts: { - restart: 'npm stop --if-present && npm start', - } }, - event: 'restart', - }, - ]) + t.match(RUN_SCRIPTS, [ + { + path: npm.localPrefix, + args: [], + scriptShell: undefined, + stdio: 'inherit', + stdioString: true, + pkg: { name: 'x', + version: '1.2.3', + _id: 'x@1.2.3', + scripts: { + restart: 'npm stop --if-present && npm start', + } }, + event: 'restart', + }, + ]) + t.end() + }) }) - RUN_SCRIPTS.length = 0 + t.end() }) -t.test('non-default env script', async t => { +t.test('non-default env script', t => { npm.localPrefix = t.testdir({ 'package.json': JSON.stringify({ name: 'x', @@ -182,54 +202,59 @@ t.test('non-default env script', async t => { }), }) - await runScript(['env'], er => { - if (er) - throw er + t.test('env', t => { + runScript.exec(['env'], er => { + if (er) + throw er - t.match(RUN_SCRIPTS, [ - { - path: npm.localPrefix, - args: [], - scriptShell: undefined, - stdio: 'inherit', - stdioString: true, - pkg: { - name: 'x', - version: '1.2.3', - _id: 'x@1.2.3', - scripts: { - env: 'hello', + t.match(RUN_SCRIPTS, [ + { + path: npm.localPrefix, + args: [], + scriptShell: undefined, + stdio: 'inherit', + stdioString: true, + pkg: { + name: 'x', + version: '1.2.3', + _id: 'x@1.2.3', + scripts: { + env: 'hello', + }, }, + event: 'env', }, - event: 'env', - }, - ]) + ]) + t.end() + }) }) - RUN_SCRIPTS.length = 0 - await runScriptWin(['env'], er => { - if (er) - throw er + t.test('env windows', t => { + runScriptWin.exec(['env'], er => { + if (er) + throw er - t.match(RUN_SCRIPTS, [ - { - path: npm.localPrefix, - args: [], - scriptShell: undefined, - stdio: 'inherit', - stdioString: true, - pkg: { name: 'x', - version: '1.2.3', - _id: 'x@1.2.3', - scripts: { - env: 'hello', + t.match(RUN_SCRIPTS, [ + { + path: npm.localPrefix, + args: [], + scriptShell: undefined, + stdio: 'inherit', + stdioString: true, + pkg: { name: 'x', + version: '1.2.3', + _id: 'x@1.2.3', + scripts: { + env: 'hello', + }, }, + event: 'env', }, - event: 'env', - }, - ]) + ]) + t.end() + }) }) - RUN_SCRIPTS.length = 0 + t.end() }) t.test('try to run missing script', t => { @@ -238,33 +263,36 @@ t.test('try to run missing script', t => { scripts: { hello: 'world' }, }), }) - t.test('no suggestions', async t => { - await runScript(['notevenclose'], er => { + t.test('no suggestions', t => { + runScript.exec(['notevenclose'], er => { t.match(er, { message: 'missing script: notevenclose', }) + t.end() }) }) - t.test('suggestions', async t => { - await runScript(['helo'], er => { + t.test('suggestions', t => { + runScript.exec(['helo'], er => { t.match(er, { message: 'missing script: helo\n\nDid you mean this?\n hello', }) + t.end() }) }) - t.test('with --if-present', async t => { + t.test('with --if-present', t => { npm.config.set('if-present', true) - await runScript(['goodbye'], er => { + runScript.exec(['goodbye'], er => { if (er) throw er t.strictSame(RUN_SCRIPTS, [], 'did not try to run anything') + t.end() }) }) t.end() }) -t.test('run pre/post hooks', async t => { +t.test('run pre/post hooks', t => { npm.localPrefix = t.testdir({ 'package.json': JSON.stringify({ name: 'x', @@ -276,7 +304,7 @@ t.test('run pre/post hooks', async t => { }), }) - await runScript(['env'], er => { + runScript.exec(['env'], er => { if (er) throw er @@ -298,11 +326,11 @@ t.test('run pre/post hooks', async t => { }, { event: 'postenv' }, ]) + t.end() }) - RUN_SCRIPTS.length = 0 }) -t.test('skip pre/post hooks when using ignoreScripts', async t => { +t.test('skip pre/post hooks when using ignoreScripts', t => { npm.flatOptions.ignoreScripts = true npm.localPrefix = t.testdir({ @@ -316,7 +344,7 @@ t.test('skip pre/post hooks when using ignoreScripts', async t => { }), }) - await runScript(['env'], er => { + runScript.exec(['env'], er => { if (er) throw er @@ -339,13 +367,12 @@ t.test('skip pre/post hooks when using ignoreScripts', async t => { event: 'env', }, ]) - + t.end() delete npm.flatOptions.ignoreScripts }) - RUN_SCRIPTS.length = 0 }) -t.test('run silent', async t => { +t.test('run silent', t => { npmlog.level = 'silent' t.teardown(() => { npmlog.level = 'warn' @@ -362,7 +389,7 @@ t.test('run silent', async t => { }), }) - await runScript(['env'], er => { + runScript.exec(['env'], er => { if (er) throw er @@ -391,11 +418,11 @@ t.test('run silent', async t => { stdio: 'inherit', }, ]) + t.end() }) - RUN_SCRIPTS.length = 0 }) -t.test('list scripts', async t => { +t.test('list scripts', t => { const scripts = { test: 'exit 2', start: 'node server.js', @@ -411,55 +438,62 @@ t.test('list scripts', async t => { }), }) - await runScript([], er => { - if (er) - throw er + t.test('no args', t => { + runScript.exec([], er => { + if (er) + throw er + t.strictSame(output, [ + ['Lifecycle scripts included in x:'], + [' test\n exit 2'], + [' start\n node server.js'], + [' stop\n node kill-server.js'], + ['\navailable via `npm run-script`:'], + [' preenv\n echo before the env'], + [' postenv\n echo after the env'], + ], 'basic report') + t.end() + }) }) - t.strictSame(output, [ - ['Lifecycle scripts included in x:'], - [' test\n exit 2'], - [' start\n node server.js'], - [' stop\n node kill-server.js'], - ['\navailable via `npm run-script`:'], - [' preenv\n echo before the env'], - [' postenv\n echo after the env'], - ], 'basic report') - output.length = 0 - npmlog.level = 'silent' - await runScript([], er => { - if (er) - throw er + t.test('silent', t => { + npmlog.level = 'silent' + runScript.exec([], er => { + if (er) + throw er + t.strictSame(output, []) + t.end() + }) }) - t.strictSame(output, []) - npmlog.level = 'warn' - - npm.flatOptions.json = true - await runScript([], er => { - if (er) - throw er + t.test('warn json', t => { + npmlog.level = 'warn' + npm.flatOptions.json = true + runScript.exec([], er => { + if (er) + throw er + t.strictSame(output, [[JSON.stringify(scripts, 0, 2)]], 'json report') + t.end() + }) }) - t.strictSame(output, [[JSON.stringify(scripts, 0, 2)]], 'json report') - output.length = 0 - npm.flatOptions.json = false - npm.flatOptions.parseable = true - await runScript([], er => { - if (er) - throw er + t.test('parseable', t => { + npm.flatOptions.parseable = true + runScript.exec([], er => { + if (er) + throw er + t.strictSame(output, [ + ['test:exit 2'], + ['start:node server.js'], + ['stop:node kill-server.js'], + ['preenv:echo before the env'], + ['postenv:echo after the env'], + ]) + t.end() + }) }) - t.strictSame(output, [ - ['test:exit 2'], - ['start:node server.js'], - ['stop:node kill-server.js'], - ['preenv:echo before the env'], - ['postenv:echo after the env'], - ]) - output.length = 0 - npm.flatOptions.parseable = false + t.end() }) -t.test('list scripts when no scripts', async t => { +t.test('list scripts when no scripts', t => { npm.localPrefix = t.testdir({ 'package.json': JSON.stringify({ name: 'x', @@ -467,15 +501,15 @@ t.test('list scripts when no scripts', async t => { }), }) - await runScript([], er => { + runScript.exec([], er => { if (er) throw er + t.strictSame(output, [], 'nothing to report') + t.end() }) - t.strictSame(output, [], 'nothing to report') - output.length = 0 }) -t.test('list scripts, only commands', async t => { +t.test('list scripts, only commands', t => { npm.localPrefix = t.testdir({ 'package.json': JSON.stringify({ name: 'x', @@ -484,18 +518,18 @@ t.test('list scripts, only commands', async t => { }), }) - await runScript([], er => { + runScript.exec([], er => { if (er) throw er + t.strictSame(output, [ + ['Lifecycle scripts included in x:'], + [' preversion\n echo doing the version dance'], + ]) + t.end() }) - t.strictSame(output, [ - ['Lifecycle scripts included in x:'], - [' preversion\n echo doing the version dance'], - ]) - output.length = 0 }) -t.test('list scripts, only non-commands', async t => { +t.test('list scripts, only non-commands', t => { npm.localPrefix = t.testdir({ 'package.json': JSON.stringify({ name: 'x', @@ -504,13 +538,13 @@ t.test('list scripts, only non-commands', async t => { }), }) - await runScript([], er => { + runScript.exec([], er => { if (er) throw er + t.strictSame(output, [ + ['Scripts available in x via `npm run-script`:'], + [' glorp\n echo doing the glerp glop'], + ]) + t.end() }) - t.strictSame(output, [ - ['Scripts available in x via `npm run-script`:'], - [' glorp\n echo doing the glerp glop'], - ]) - output.length = 0 }) diff --git a/test/lib/search.js b/test/lib/search.js index 1dba1250e..59c59f3b9 100644 --- a/test/lib/search.js +++ b/test/lib/search.js @@ -23,7 +23,6 @@ const libnpmsearch = { const mocks = { npmlog, libnpmsearch, - '../../lib/npm.js': npm, '../../lib/utils/output.js': (...msg) => { result += msg.join('\n') }, @@ -37,10 +36,11 @@ t.afterEach(cb => { cb() }) -const search = requireInject('../../lib/search.js', mocks) +const Search = requireInject('../../lib/search.js', mocks) +const search = new Search(npm) t.test('no args', t => { - search([], err => { + search.exec([], err => { t.match( err, /search must be called with arguments/, @@ -59,12 +59,13 @@ t.test('search <name>', t => { }, } - const search = requireInject('../../lib/search.js', { + const Search = requireInject('../../lib/search.js', { ...mocks, libnpmsearch, }) + const search = new Search(npm) - search(['libnpm'], err => { + search.exec(['libnpm'], err => { if (err) throw err @@ -93,12 +94,13 @@ t.test('search <name> --searchexclude --searchopts', t => { }, } - const search = requireInject('../../lib/search.js', { + const Search = requireInject('../../lib/search.js', { ...mocks, libnpmsearch, }) + const search = new Search(npm) - search(['foo'], err => { + search.exec(['foo'], err => { if (err) throw err @@ -146,12 +148,13 @@ t.test('empty search results', t => { }, } - const search = requireInject('../../lib/search.js', { + const Search = requireInject('../../lib/search.js', { ...mocks, libnpmsearch, }) + const search = new Search(npm) - search(['foo'], err => { + search.exec(['foo'], err => { if (err) throw err @@ -172,12 +175,13 @@ t.test('search api response error', t => { }, } - const search = requireInject('../../lib/search.js', { + const Search = requireInject('../../lib/search.js', { ...mocks, libnpmsearch, }) + const search = new Search(npm) - search(['foo'], err => { + search.exec(['foo'], err => { t.match( err, /ERR/, diff --git a/test/lib/set-script.js b/test/lib/set-script.js index 196fd3d3e..7a057c503 100644 --- a/test/lib/set-script.js +++ b/test/lib/set-script.js @@ -1,54 +1,50 @@ const test = require('tap') const requireInject = require('require-inject') -const setScriptDefault = require('../../lib/set-script.js') const parseJSON = require('json-parse-even-better-errors') -test.type(setScriptDefault, 'function', 'command is function') -test.equal(setScriptDefault.usage, 'npm set-script [<script>] [<command>]', 'usage matches') test.test('fails on invalid arguments', (t) => { - const setScript = requireInject('../../lib/set-script.js', { - fs: {}, + const SetScript = requireInject('../../lib/set-script.js', { npmlog: {}, }) + const setScript = new SetScript({}) t.plan(3) - setScript(['arg1'], (fail) => t.match(fail, /Expected 2 arguments: got 1/)) - setScript(['arg1', 'arg2', 'arg3'], (fail) => t.match(fail, /Expected 2 arguments: got 3/)) - setScript(['arg1', 'arg2', 'arg3', 'arg4'], (fail) => t.match(fail, /Expected 2 arguments: got 4/)) + setScript.exec(['arg1'], (fail) => t.match(fail, /Expected 2 arguments: got 1/)) + setScript.exec(['arg1', 'arg2', 'arg3'], (fail) => t.match(fail, /Expected 2 arguments: got 3/)) + setScript.exec(['arg1', 'arg2', 'arg3', 'arg4'], (fail) => t.match(fail, /Expected 2 arguments: got 4/)) }) test.test('fails if run in postinstall script', (t) => { - var originalVar = process.env.npm_lifecycle_event + const originalVar = process.env.npm_lifecycle_event process.env.npm_lifecycle_event = 'postinstall' - const setScript = requireInject('../../lib/set-script.js', { - fs: {}, + const SetScript = requireInject('../../lib/set-script.js', { npmlog: {}, }) t.plan(1) - setScript(['arg1', 'arg2'], (fail) => t.equal(fail.toString(), 'Error: Scripts can’t set from the postinstall script')) + const setScript = new SetScript({}) + setScript.exec(['arg1', 'arg2'], (fail) => t.equal(fail.toString(), 'Error: Scripts can’t set from the postinstall script')) process.env.npm_lifecycle_event = originalVar }) test.test('fails when package.json not found', (t) => { - const setScript = requireInject('../../lib/set-script.js', { - '../../lib/npm.js': { - localPrefix: 'IDONTEXIST', - }, - }) + const SetScript = requireInject('../../lib/set-script.js') + const setScript = new SetScript({}) t.plan(1) - setScript(['arg1', 'arg2'], (fail) => t.match(fail, /package.json not found/)) + setScript.exec(['arg1', 'arg2'], (fail) => t.match(fail, /package.json not found/)) }) test.test('fails on invalid JSON', (t) => { - const setScript = requireInject('../../lib/set-script.js', { + const SetScript = requireInject('../../lib/set-script.js', { fs: { + readFile: () => {}, // read-package-json-fast explodes w/o this readFileSync: (name, charcode) => { return 'iamnotjson' }, }, }) + const setScript = new SetScript({}) t.plan(1) - setScript(['arg1', 'arg2'], (fail) => t.match(fail, /Invalid package.json: JSONParseError/)) + setScript.exec(['arg1', 'arg2'], (fail) => t.match(fail, /Invalid package.json: JSONParseError/)) }) test.test('creates scripts object', (t) => { var mockFile = '' - const setScript = requireInject('../../lib/set-script.js', { + const SetScript = requireInject('../../lib/set-script.js', { fs: { readFileSync: (name, charcode) => { return '{}' @@ -64,15 +60,16 @@ test.test('creates scripts object', (t) => { } }, }) + const setScript = new SetScript({}) t.plan(2) - setScript(['arg1', 'arg2'], (error) => { + setScript.exec(['arg1', 'arg2'], (error) => { t.equal(error, undefined) t.assert(parseJSON(mockFile), {scripts: {arg1: 'arg2'}}) }) }) test.test('warns before overwriting', (t) => { var warningListened = '' - const setScript = requireInject('../../lib/set-script.js', { + const SetScript = requireInject('../../lib/set-script.js', { fs: { readFileSync: (name, charcode) => { return JSON.stringify({ @@ -95,15 +92,16 @@ test.test('warns before overwriting', (t) => { }, }, }) + const setScript = new SetScript({}) t.plan(2) - setScript(['arg1', 'arg2'], (error) => { + setScript.exec(['arg1', 'arg2'], (error) => { t.equal(error, undefined, 'no error') t.equal(warningListened, 'Script "arg1" was overwritten') }) }) test.test('provided indentation and eol is used', (t) => { var mockFile = '' - const setScript = requireInject('../../lib/set-script.js', { + const SetScript = requireInject('../../lib/set-script.js', { fs: { readFileSync: (name, charcode) => { return '{}' @@ -119,8 +117,9 @@ test.test('provided indentation and eol is used', (t) => { } }, }) + const setScript = new SetScript({}) t.plan(3) - setScript(['arg1', 'arg2'], (error) => { + setScript.exec(['arg1', 'arg2'], (error) => { t.equal(error, undefined) t.equal(mockFile.split('\r\n').length > 1, true) t.equal(mockFile.split('\r\n').every((value) => !value.startsWith(' ') || value.startsWith(' '.repeat(6))), true) @@ -128,7 +127,7 @@ test.test('provided indentation and eol is used', (t) => { }) test.test('goes to default when undefined indent and eol provided', (t) => { var mockFile = '' - const setScript = requireInject('../../lib/set-script.js', { + const SetScript = requireInject('../../lib/set-script.js', { fs: { readFileSync: (name, charcode) => { return '{}' @@ -144,8 +143,9 @@ test.test('goes to default when undefined indent and eol provided', (t) => { } }, }) + const setScript = new SetScript({}) t.plan(3) - setScript(['arg1', 'arg2'], (error) => { + setScript.exec(['arg1', 'arg2'], (error) => { t.equal(error, undefined) t.equal(mockFile.split('\n').length > 1, true) t.equal(mockFile.split('\n').every((value) => !value.startsWith(' ') || value.startsWith(' ')), true) diff --git a/test/lib/set.js b/test/lib/set.js index aeb239e9c..3b38fdc27 100644 --- a/test/lib/set.js +++ b/test/lib/set.js @@ -1,4 +1,4 @@ -const { test } = require('tap') +const t = require('tap') const requireInject = require('require-inject') let configArgs = null @@ -6,24 +6,23 @@ const npm = { commands: { config: (args, cb) => { configArgs = args - return cb() + cb() }, }, } -const set = requireInject('../../lib/set.js', { - '../../lib/npm.js': npm, -}) +const Set = requireInject('../../lib/set.js') +const set = new Set(npm) -test('npm set - no args', t => { - return set([], (err) => { +t.test('npm set - no args', t => { + set.exec([], (err) => { t.match(err, /npm set/, 'prints usage') t.end() }) }) -test('npm set', t => { - return set(['email', 'me@me.me'], (err) => { +t.test('npm set', t => { + set.exec(['email', 'me@me.me'], (err) => { if (err) throw err diff --git a/test/lib/shrinkwrap.js b/test/lib/shrinkwrap.js index 51fd7931a..dc4bc3b22 100644 --- a/test/lib/shrinkwrap.js +++ b/test/lib/shrinkwrap.js @@ -31,7 +31,6 @@ const mocks = { return tree } }, - '../../lib/npm.js': npm, '../../lib/utils/usage.js': () => 'usage instructions', } @@ -80,13 +79,14 @@ t.test('no args', t => { }, } - const shrinkwrap = requireInject('../../lib/shrinkwrap.js', { + const Shrinkwrap = requireInject('../../lib/shrinkwrap.js', { ...mocks, npmlog, '@npmcli/arborist': Arborist, }) + const shrinkwrap = new Shrinkwrap(npm) - shrinkwrap([], err => { + shrinkwrap.exec([], err => { if (err) throw err }) @@ -134,13 +134,14 @@ t.test('no virtual tree', t => { }, } - const shrinkwrap = requireInject('../../lib/shrinkwrap.js', { + const Shrinkwrap = requireInject('../../lib/shrinkwrap.js', { ...mocks, npmlog, '@npmcli/arborist': Arborist, }) + const shrinkwrap = new Shrinkwrap(npm) - shrinkwrap([], err => { + shrinkwrap.exec([], err => { if (err) throw err }) @@ -194,14 +195,15 @@ t.test('existing package-json file', t => { }, } - const shrinkwrap = requireInject('../../lib/shrinkwrap.js', { + const Shrinkwrap = requireInject('../../lib/shrinkwrap.js', { ...mocks, fs, npmlog, '@npmcli/arborist': Arborist, }) + const shrinkwrap = new Shrinkwrap(npm) - shrinkwrap([], err => { + shrinkwrap.exec([], err => { if (err) throw err }) @@ -248,13 +250,14 @@ t.test('update shrinkwrap file version', t => { }, } - const shrinkwrap = requireInject('../../lib/shrinkwrap.js', { + const Shrinkwrap = requireInject('../../lib/shrinkwrap.js', { ...mocks, npmlog, '@npmcli/arborist': Arborist, }) + const shrinkwrap = new Shrinkwrap(npm) - shrinkwrap([], err => { + shrinkwrap.exec([], err => { if (err) throw err }) @@ -301,24 +304,26 @@ t.test('update to date shrinkwrap file', t => { }, } - const shrinkwrap = requireInject('../../lib/shrinkwrap.js', { + const Shrinkwrap = requireInject('../../lib/shrinkwrap.js', { ...mocks, npmlog, '@npmcli/arborist': Arborist, }) + const shrinkwrap = new Shrinkwrap(npm) - shrinkwrap([], err => { + shrinkwrap.exec([], err => { if (err) throw err }) }) t.test('shrinkwrap --global', t => { - const shrinkwrap = requireInject('../../lib/shrinkwrap.js', mocks) + const Shrinkwrap = requireInject('../../lib/shrinkwrap.js', mocks) npm.flatOptions.global = true + const shrinkwrap = new Shrinkwrap(npm) - shrinkwrap([], err => { + shrinkwrap.exec([], err => { t.match( err, /does not work for global packages/, @@ -330,8 +335,11 @@ t.test('shrinkwrap --global', t => { }) t.test('works without fs.promises', async t => { - t.doesNotThrow(() => requireInject('../../lib/shrinkwrap.js', { - ...mocks, - fs: { ...fs, promises: null }, - })) + t.doesNotThrow(() => { + const Shrinkwrap = requireInject('../../lib/shrinkwrap.js', { + ...mocks, + fs: { ...fs, promises: null }, + }) + new Shrinkwrap(npm) + }) }) diff --git a/test/lib/star.js b/test/lib/star.js index ea5e07b94..64efd9ef8 100644 --- a/test/lib/star.js +++ b/test/lib/star.js @@ -10,7 +10,6 @@ const npmlog = { error: noop, info: noop, verbose: noop } const mocks = { npmlog, 'npm-registry-fetch': npmFetch, - '../../lib/npm.js': npm, '../../lib/utils/output.js': (...msg) => { result += msg.join('\n') }, @@ -18,7 +17,8 @@ const mocks = { '../../lib/utils/usage.js': () => 'usage instructions', } -const star = requireInject('../../lib/star.js', mocks) +const Star = requireInject('../../lib/star.js', mocks) +const star = new Star(npm) t.afterEach(cb => { npm.config = { get () {} } @@ -29,7 +29,7 @@ t.afterEach(cb => { }) t.test('no args', t => { - star([], err => { + star.exec([], err => { t.match( err, /usage instructions/, @@ -56,7 +56,7 @@ t.test('star a package', t => { t.equal(msg, 'starring', 'should use expected msg') t.equal(id, pkgName, 'should use expected id') } - star([pkgName], err => { + star.exec([pkgName], err => { if (err) throw err t.equal( @@ -84,7 +84,7 @@ t.test('unstar a package', t => { t.equal(msg, 'unstarring', 'should use expected msg') t.equal(id, pkgName, 'should use expected id') } - star([pkgName], err => { + star.exec([pkgName], err => { if (err) throw err t.equal( @@ -99,7 +99,7 @@ t.test('unicode', async t => { t.test('star a package', t => { npm.flatOptions.unicode = true npmFetch.json = async (uri, opts) => ({}) - star(['pkg'], err => { + star.exec(['pkg'], err => { if (err) throw err t.equal( @@ -115,7 +115,7 @@ t.test('unicode', async t => { npm.flatOptions.unicode = true npm.config.get = key => key === 'star.unstar' npmFetch.json = async (uri, opts) => ({}) - star(['pkg'], err => { + star.exec(['pkg'], err => { if (err) throw err t.equal( @@ -129,11 +129,12 @@ t.test('unicode', async t => { }) t.test('logged out user', t => { - const star = requireInject('../../lib/star.js', { + const Star = requireInject('../../lib/star.js', { ...mocks, '../../lib/utils/get-identity.js': async () => undefined, }) - star(['@npmcli/arborist'], err => { + const star = new Star(npm) + star.exec(['@npmcli/arborist'], err => { t.match( err, /You need to be logged in/, diff --git a/test/lib/stars.js b/test/lib/stars.js index ff636a5e5..383b5adf4 100644 --- a/test/lib/stars.js +++ b/test/lib/stars.js @@ -10,7 +10,6 @@ const npmlog = { warn: noop } const mocks = { npmlog, 'npm-registry-fetch': npmFetch, - '../../lib/npm.js': npm, '../../lib/utils/output.js': (...msg) => { result = [result, ...msg].join('\n') }, @@ -18,7 +17,8 @@ const mocks = { '../../lib/utils/usage.js': () => 'usage instructions', } -const stars = requireInject('../../lib/stars.js', mocks) +const Stars = requireInject('../../lib/stars.js', mocks) +const stars = new Stars(npm) t.afterEach(cb => { npm.config = { get () {} } @@ -43,7 +43,7 @@ t.test('no args', t => { } } - stars([], err => { + stars.exec([], err => { if (err) throw err @@ -67,7 +67,7 @@ t.test('npm star <user>', t => { } } - stars(['ruyadorno'], err => { + stars.exec(['ruyadorno'], err => { if (err) throw err @@ -97,7 +97,7 @@ t.test('unauthorized request', t => { ) } - stars([], err => { + stars.exec([], err => { t.match( err, /Not logged in/, @@ -121,7 +121,7 @@ t.test('unexpected error', t => { throw new Error('Should not output extra warning msgs') } - stars([], err => { + stars.exec([], err => { t.match( err, /ERROR/, @@ -144,7 +144,7 @@ t.test('no pkg starred', t => { ) } - stars([], err => { + stars.exec([], err => { if (err) throw err }) diff --git a/test/lib/start.js b/test/lib/start.js index 4f599223d..9a3328309 100644 --- a/test/lib/start.js +++ b/test/lib/start.js @@ -1,4 +1,17 @@ const t = require('tap') -const start = require('../../lib/start.js') -t.isa(start, Function) +let runArgs +const npm = { + commands: { + 'run-script': (args, cb) => { + runArgs = args + cb() + }, + }, +} +const Start = require('../../lib/start.js') +const start = new Start(npm) t.equal(start.usage, 'npm start [-- <args>]') +start.exec(['foo'], () => { + t.match(runArgs, ['start', 'foo']) + t.end() +}) diff --git a/test/lib/stop.js b/test/lib/stop.js index 4e26703c9..e6cb193b6 100644 --- a/test/lib/stop.js +++ b/test/lib/stop.js @@ -1,4 +1,17 @@ const t = require('tap') -const stop = require('../../lib/stop.js') -t.isa(stop, Function) +let runArgs +const npm = { + commands: { + 'run-script': (args, cb) => { + runArgs = args + cb() + }, + }, +} +const Stop = require('../../lib/stop.js') +const stop = new Stop(npm) t.equal(stop.usage, 'npm stop [-- <args>]') +stop.exec(['foo'], () => { + t.match(runArgs, ['stop', 'foo']) + t.end() +}) diff --git a/test/lib/team.js b/test/lib/team.js index 9edaf58ee..a26459725 100644 --- a/test/lib/team.js +++ b/test/lib/team.js @@ -14,7 +14,6 @@ const npm = { flatOptions: {} } const mocks = { libnpmteam, 'cli-columns': a => a.join(' '), - '../../lib/npm.js': npm, '../../lib/utils/output.js': (...msg) => { result += msg.join('\n') }, @@ -28,10 +27,11 @@ t.afterEach(cb => { cb() }) -const team = requireInject('../../lib/team.js', mocks) +const Team = requireInject('../../lib/team.js', mocks) +const team = new Team(npm) t.test('no args', t => { - team([], err => { + team.exec([], err => { t.match( err, 'usage instructions', @@ -43,7 +43,7 @@ t.test('no args', t => { t.test('team add <scope:team> <user>', t => { t.test('default output', t => { - team(['add', '@npmcli:developers', 'foo'], err => { + team.exec(['add', '@npmcli:developers', 'foo'], err => { if (err) throw err @@ -55,7 +55,7 @@ t.test('team add <scope:team> <user>', t => { t.test('--parseable', t => { npm.flatOptions.parseable = true - team(['add', '@npmcli:developers', 'foo'], err => { + team.exec(['add', '@npmcli:developers', 'foo'], err => { if (err) throw err @@ -70,7 +70,7 @@ t.test('team add <scope:team> <user>', t => { t.test('--json', t => { npm.flatOptions.json = true - team(['add', '@npmcli:developers', 'foo'], err => { + team.exec(['add', '@npmcli:developers', 'foo'], err => { if (err) throw err @@ -90,7 +90,7 @@ t.test('team add <scope:team> <user>', t => { t.test('--silent', t => { npm.flatOptions.silent = true - team(['add', '@npmcli:developers', 'foo'], err => { + team.exec(['add', '@npmcli:developers', 'foo'], err => { if (err) throw err @@ -104,7 +104,7 @@ t.test('team add <scope:team> <user>', t => { t.test('team create <scope:team>', t => { t.test('default output', t => { - team(['create', '@npmcli:newteam'], err => { + team.exec(['create', '@npmcli:newteam'], err => { if (err) throw err @@ -116,7 +116,7 @@ t.test('team create <scope:team>', t => { t.test('--parseable', t => { npm.flatOptions.parseable = true - team(['create', '@npmcli:newteam'], err => { + team.exec(['create', '@npmcli:newteam'], err => { if (err) throw err @@ -131,7 +131,7 @@ t.test('team create <scope:team>', t => { t.test('--json', t => { npm.flatOptions.json = true - team(['create', '@npmcli:newteam'], err => { + team.exec(['create', '@npmcli:newteam'], err => { if (err) throw err @@ -150,7 +150,7 @@ t.test('team create <scope:team>', t => { t.test('--silent', t => { npm.flatOptions.silent = true - team(['create', '@npmcli:newteam'], err => { + team.exec(['create', '@npmcli:newteam'], err => { if (err) throw err @@ -164,7 +164,7 @@ t.test('team create <scope:team>', t => { t.test('team destroy <scope:team>', t => { t.test('default output', t => { - team(['destroy', '@npmcli:newteam'], err => { + team.exec(['destroy', '@npmcli:newteam'], err => { if (err) throw err @@ -176,7 +176,7 @@ t.test('team destroy <scope:team>', t => { t.test('--parseable', t => { npm.flatOptions.parseable = true - team(['destroy', '@npmcli:newteam'], err => { + team.exec(['destroy', '@npmcli:newteam'], err => { if (err) throw err @@ -188,7 +188,7 @@ t.test('team destroy <scope:team>', t => { t.test('--json', t => { npm.flatOptions.json = true - team(['destroy', '@npmcli:newteam'], err => { + team.exec(['destroy', '@npmcli:newteam'], err => { if (err) throw err @@ -207,7 +207,7 @@ t.test('team destroy <scope:team>', t => { t.test('--silent', t => { npm.flatOptions.silent = true - team(['destroy', '@npmcli:newteam'], err => { + team.exec(['destroy', '@npmcli:newteam'], err => { if (err) throw err @@ -230,13 +230,14 @@ t.test('team ls <scope>', t => { }, } - const team = requireInject('../../lib/team.js', { + const Team = requireInject('../../lib/team.js', { ...mocks, libnpmteam, }) + const team = new Team(npm) t.test('default output', t => { - team(['ls', '@npmcli'], err => { + team.exec(['ls', '@npmcli'], err => { if (err) throw err @@ -248,7 +249,7 @@ t.test('team ls <scope>', t => { t.test('--parseable', t => { npm.flatOptions.parseable = true - team(['ls', '@npmcli'], err => { + team.exec(['ls', '@npmcli'], err => { if (err) throw err @@ -260,7 +261,7 @@ t.test('team ls <scope>', t => { t.test('--json', t => { npm.flatOptions.json = true - team(['ls', '@npmcli'], err => { + team.exec(['ls', '@npmcli'], err => { if (err) throw err @@ -280,7 +281,7 @@ t.test('team ls <scope>', t => { t.test('--silent', t => { npm.flatOptions.silent = true - team(['ls', '@npmcli'], err => { + team.exec(['ls', '@npmcli'], err => { if (err) throw err @@ -296,12 +297,13 @@ t.test('team ls <scope>', t => { }, } - const team = requireInject('../../lib/team.js', { + const Team = requireInject('../../lib/team.js', { ...mocks, libnpmteam, }) + const team = new Team(npm) - team(['ls', '@npmcli'], err => { + team.exec(['ls', '@npmcli'], err => { if (err) throw err @@ -317,12 +319,13 @@ t.test('team ls <scope>', t => { }, } - const team = requireInject('../../lib/team.js', { + const Team = requireInject('../../lib/team.js', { ...mocks, libnpmteam, }) + const team = new Team(npm) - team(['ls', '@npmcli'], err => { + team.exec(['ls', '@npmcli'], err => { if (err) throw err @@ -340,13 +343,14 @@ t.test('team ls <scope:team>', t => { return ['nlf', 'ruyadorno', 'darcyclarke', 'isaacs'] }, } - const team = requireInject('../../lib/team.js', { + const Team = requireInject('../../lib/team.js', { ...mocks, libnpmteam, }) + const team = new Team(npm) t.test('default output', t => { - team(['ls', '@npmcli:developers'], err => { + team.exec(['ls', '@npmcli:developers'], err => { if (err) throw err @@ -358,7 +362,7 @@ t.test('team ls <scope:team>', t => { t.test('--parseable', t => { npm.flatOptions.parseable = true - team(['ls', '@npmcli:developers'], err => { + team.exec(['ls', '@npmcli:developers'], err => { if (err) throw err @@ -370,7 +374,7 @@ t.test('team ls <scope:team>', t => { t.test('--json', t => { npm.flatOptions.json = true - team(['ls', '@npmcli:developers'], err => { + team.exec(['ls', '@npmcli:developers'], err => { if (err) throw err @@ -391,7 +395,7 @@ t.test('team ls <scope:team>', t => { t.test('--silent', t => { npm.flatOptions.silent = true - team(['ls', '@npmcli:developers'], err => { + team.exec(['ls', '@npmcli:developers'], err => { if (err) throw err @@ -407,12 +411,13 @@ t.test('team ls <scope:team>', t => { }, } - const team = requireInject('../../lib/team.js', { + const Team = requireInject('../../lib/team.js', { ...mocks, libnpmteam, }) + const team = new Team(npm) - team(['ls', '@npmcli:developers'], err => { + team.exec(['ls', '@npmcli:developers'], err => { if (err) throw err @@ -428,12 +433,13 @@ t.test('team ls <scope:team>', t => { }, } - const team = requireInject('../../lib/team.js', { + const Team = requireInject('../../lib/team.js', { ...mocks, libnpmteam, }) + const team = new Team(npm) - team(['ls', '@npmcli:developers'], err => { + team.exec(['ls', '@npmcli:developers'], err => { if (err) throw err @@ -447,7 +453,7 @@ t.test('team ls <scope:team>', t => { t.test('team rm <scope:team> <user>', t => { t.test('default output', t => { - team(['rm', '@npmcli:newteam', 'foo'], err => { + team.exec(['rm', '@npmcli:newteam', 'foo'], err => { if (err) throw err @@ -459,7 +465,7 @@ t.test('team rm <scope:team> <user>', t => { t.test('--parseable', t => { npm.flatOptions.parseable = true - team(['rm', '@npmcli:newteam', 'foo'], err => { + team.exec(['rm', '@npmcli:newteam', 'foo'], err => { if (err) throw err @@ -471,7 +477,7 @@ t.test('team rm <scope:team> <user>', t => { t.test('--json', t => { npm.flatOptions.json = true - team(['rm', '@npmcli:newteam', 'foo'], err => { + team.exec(['rm', '@npmcli:newteam', 'foo'], err => { if (err) throw err @@ -491,7 +497,7 @@ t.test('team rm <scope:team> <user>', t => { t.test('--silent', t => { npm.flatOptions.silent = true - team(['rm', '@npmcli:newteam', 'foo'], err => { + team.exec(['rm', '@npmcli:newteam', 'foo'], err => { if (err) throw err diff --git a/test/lib/test.js b/test/lib/test.js index 6f4a7395d..f6f3d7afb 100644 --- a/test/lib/test.js +++ b/test/lib/test.js @@ -1,7 +1,7 @@ const t = require('tap') const requireInject = require('require-inject') let RUN_ARGS = null -const npmock = { +const npm = { commands: { 'run-script': (args, cb) => { RUN_ARGS = args @@ -9,15 +9,14 @@ const npmock = { }, }, } -const test = requireInject('../../lib/test.js', { - '../../lib/npm.js': npmock, -}) +const Test = requireInject('../../lib/test.js') +const test = new Test(npm) t.test('run a test', t => { - test([], (er) => { + test.exec([], (er) => { t.strictSame(RUN_ARGS, ['test'], 'added "test" to the args') }) - test(['hello', 'world'], (er) => { + test.exec(['hello', 'world'], (er) => { t.strictSame(RUN_ARGS, ['test', 'hello', 'world'], 'added positional args') }) @@ -26,13 +25,13 @@ t.test('run a test', t => { }) const otherErr = new Error('should see this') - npmock.commands['run-script'] = (args, cb) => cb(lcErr) - test([], (er) => { + npm.commands['run-script'] = (args, cb) => cb(lcErr) + test.exec([], (er) => { t.equal(er, 'Test failed. See above for more details.') }) - npmock.commands['run-script'] = (args, cb) => cb(otherErr) - test([], (er) => { + npm.commands['run-script'] = (args, cb) => cb(otherErr) + test.exec([], (er) => { t.match(er, { message: 'should see this' }) }) diff --git a/test/lib/token.js b/test/lib/token.js index 6ab841f49..412d2746b 100644 --- a/test/lib/token.js +++ b/test/lib/token.js @@ -2,15 +2,13 @@ const { test } = require('tap') const requireInject = require('require-inject') const mocks = { - npm: {}, profile: {}, output: () => {}, log: {}, readUserInfo: {}, } -const tokenMock = requireInject('../../lib/token.js', { - '../../lib/npm.js': mocks.npm, +const Token = requireInject('../../lib/token.js', { '../../lib/utils/output.js': (...args) => mocks.output(...args), '../../lib/utils/otplease.js': (opts, fn) => { return Promise.resolve().then(() => fn(opts)) @@ -19,36 +17,42 @@ const tokenMock = requireInject('../../lib/token.js', { 'npm-profile': mocks.profile, npmlog: mocks.log, }) +const token = new Token({}) const tokenWithMocks = (mockRequests) => { for (const mod in mockRequests) { - if (typeof mockRequests[mod] === 'function') - mocks[mod] = mockRequests[mod] - else { - for (const key in mockRequests[mod]) - mocks[mod][key] = mockRequests[mod][key] + if (mod !== 'npm') { + if (typeof mockRequests[mod] === 'function') + mocks[mod] = mockRequests[mod] + else { + for (const key in mockRequests[mod]) + mocks[mod][key] = mockRequests[mod][key] + } } } const reset = () => { for (const mod in mockRequests) { - if (typeof mockRequests[mod] === 'function') - mocks[mod] = () => {} - else { - for (const key in mockRequests[mod]) - delete mocks[mod][key] + if (mod !== 'npm') { + if (typeof mockRequests[mod] === 'function') + mocks[mod] = () => {} + else { + for (const key in mockRequests[mod]) + delete mocks[mod][key] + } } } } - return [tokenMock, reset] + const token = new Token(mockRequests.npm || {}) + return [token, reset] } test('completion', (t) => { t.plan(5) const testComp = (argv, expect) => { - t.resolveMatch(tokenMock.completion({ conf: { argv: { remain: argv } } }), expect, argv.join(' ')) + t.resolveMatch(token.completion({ conf: { argv: { remain: argv } } }), expect, argv.join(' ')) } testComp(['npm', 'token'], ['list', 'revoke', 'create']) @@ -57,7 +61,7 @@ test('completion', (t) => { testComp(['npm', 'token', 'create'], []) t.rejects( - tokenMock.completion({ conf: { argv: { remain: ['npm', 'token', 'foobar'] } } }), + token.completion({ conf: { argv: { remain: ['npm', 'token', 'foobar'] } } }), { message: 'foobar not recognize' } ) }) @@ -77,7 +81,7 @@ test('token foobar', (t) => { t.tearDown(reset) - tokenMock(['foobar'], (err) => { + token.exec(['foobar'], (err) => { t.match(err.message, 'foobar is not a recognized subcommand') }) }) @@ -145,7 +149,7 @@ test('token list', (t) => { t.tearDown(reset) - token([], (err) => { + token.exec([], (err) => { t.ifError(err, 'npm token list') }) }) @@ -199,7 +203,7 @@ test('token list json output', (t) => { t.tearDown(reset) - token(['list'], (err) => { + token.exec(['list'], (err) => { t.ifError(err, 'npm token list') }) }) @@ -267,7 +271,7 @@ test('token list parseable output', (t) => { t.tearDown(reset) - token(['list'], (err) => { + token.exec(['list'], (err) => { t.ifError(err, 'npm token list') }) }) @@ -320,7 +324,7 @@ test('token revoke', (t) => { t.tearDown(reset) - token(['rm', 'abcd'], (err) => { + token.exec(['rm', 'abcd'], (err) => { t.ifError(err, 'npm token rm') }) }) @@ -372,7 +376,7 @@ test('token revoke multiple tokens', (t) => { t.tearDown(reset) - token(['revoke', 'abcd', 'efgh'], (err) => { + token.exec(['revoke', 'abcd', 'efgh'], (err) => { t.ifError(err, 'npm token rm') }) }) @@ -424,7 +428,7 @@ test('token revoke json output', (t) => { t.tearDown(reset) - token(['delete', 'abcd'], (err) => { + token.exec(['delete', 'abcd'], (err) => { t.ifError(err, 'npm token rm') }) }) @@ -474,7 +478,7 @@ test('token revoke parseable output', (t) => { t.tearDown(reset) - token(['remove', 'abcd'], (err) => { + token.exec(['remove', 'abcd'], (err) => { t.ifError(err, 'npm token rm') }) }) @@ -524,7 +528,7 @@ test('token revoke by token', (t) => { t.tearDown(reset) - token(['rm', 'efgh5678'], (err) => { + token.exec(['rm', 'efgh5678'], (err) => { t.ifError(err, 'npm token rm') }) }) @@ -544,7 +548,7 @@ test('token revoke requires an id', (t) => { t.tearDown(reset) - token(['rm'], (err) => { + token.exec(['rm'], (err) => { t.match(err.message, '`<tokenKey>` argument is required') }) }) @@ -589,7 +593,7 @@ test('token revoke ambiguous id errors', (t) => { t.tearDown(reset) - token(['rm', 'abcd'], (err) => { + token.exec(['rm', 'abcd'], (err) => { t.match(err.message, 'Token ID "abcd" was ambiguous') }) }) @@ -633,7 +637,7 @@ test('token revoke unknown id errors', (t) => { t.tearDown(reset) - token(['rm', 'efgh'], (err) => { + token.exec(['rm', 'efgh'], (err) => { t.match(err.message, 'Unknown token id or value "efgh".') }) }) @@ -697,7 +701,7 @@ test('token create', (t) => { t.tearDown(reset) - token(['create'], (err) => { + token.exec(['create'], (err) => { t.ifError(err, 'npm token create') }) }) @@ -756,7 +760,7 @@ test('token create json output', (t) => { t.tearDown(reset) - token(['create'], (err) => { + token.exec(['create'], (err) => { t.ifError(err, 'npm token create') }) }) @@ -822,7 +826,7 @@ test('token create parseable output', (t) => { t.tearDown(reset) - token(['create'], (err) => { + token.exec(['create'], (err) => { t.ifError(err, 'npm token create') }) }) @@ -856,7 +860,7 @@ test('token create ipv6 cidr', (t) => { t.tearDown(reset) - token(['create'], (err) => { + token.exec(['create'], (err) => { t.equal(err.message, 'CIDR whitelist can only contain IPv4 addresses, ::1/128 is IPv6', 'returns correct error') t.equal(err.code, 'EINVALIDCIDR') }) @@ -891,7 +895,7 @@ test('token create invalid cidr', (t) => { t.tearDown(reset) - token(['create'], (err) => { + token.exec(['create'], (err) => { t.equal(err.message, 'CIDR whitelist contains invalid CIDR entry: apple/cider', 'returns correct error') t.equal(err.code, 'EINVALIDCIDR') }) diff --git a/test/lib/uninstall.js b/test/lib/uninstall.js index 69040c0f2..c62b59950 100644 --- a/test/lib/uninstall.js +++ b/test/lib/uninstall.js @@ -12,12 +12,12 @@ const npm = { localPrefix: '', } const mocks = { - '../../lib/npm.js': npm, '../../lib/utils/reify-finish.js': () => Promise.resolve(), '../../lib/utils/usage.js': () => 'usage instructions', } -const uninstall = requireInject('../../lib/uninstall.js', mocks) +const Uninstall = requireInject('../../lib/uninstall.js', mocks) +const uninstall = new Uninstall(npm) t.afterEach(cb => { npm.globalDir = '' @@ -87,7 +87,7 @@ t.test('remove single installed lib', t => { npm.flatOptions.prefix = path - uninstall(['b'], err => { + uninstall.exec(['b'], err => { if (err) throw err @@ -150,7 +150,7 @@ t.test('remove multiple installed libs', t => { npm.flatOptions.prefix = path - uninstall(['b'], err => { + uninstall.exec(['b'], err => { if (err) throw err @@ -165,7 +165,7 @@ t.test('no args local', t => { npm.flatOptions.prefix = path - uninstall([], err => { + uninstall.exec([], err => { t.match( err, /Must provide a package name to remove/, @@ -201,7 +201,7 @@ t.test('no args global', t => { const a = resolve(path, 'lib/node_modules/a') t.ok(() => fs.statSync(a)) - uninstall([], err => { + uninstall.exec([], err => { if (err) throw err @@ -218,7 +218,7 @@ t.test('no args global but no package.json', t => { npm.localPrefix = path npm.flatOptions.global = true - uninstall([], err => { + uninstall.exec([], err => { t.match( err, 'usage instructions', @@ -232,16 +232,17 @@ t.test('no args global but no package.json', t => { t.test('unknown error reading from localPrefix package.json', t => { const path = t.testdir({}) - const uninstall = requireInject('../../lib/uninstall.js', { + const Uninstall = requireInject('../../lib/uninstall.js', { ...mocks, 'read-package-json-fast': () => Promise.reject(new Error('ERR')), }) + const uninstall = new Uninstall(npm) npm.prefix = path npm.localPrefix = path npm.flatOptions.global = true - uninstall([], err => { + uninstall.exec([], err => { t.match( err, /ERR/, diff --git a/test/lib/unpublish.js b/test/lib/unpublish.js index c1fbed57e..80a879cb6 100644 --- a/test/lib/unpublish.js +++ b/test/lib/unpublish.js @@ -18,7 +18,6 @@ const mocks = { 'npm-package-arg': noop, 'npm-registry-fetch': { json: noop }, 'read-package-json': cb => cb(), - '../../lib/npm.js': npm, '../../lib/utils/output.js': (...msg) => { result += msg.join('\n') }, @@ -78,7 +77,7 @@ t.test('no args --force', t => { }, } - const unpublish = requireInject('../../lib/unpublish.js', { + const Unpublish = requireInject('../../lib/unpublish.js', { ...mocks, npmlog, libnpmpublish, @@ -88,8 +87,9 @@ t.test('no args --force', t => { version: '1.0.0', }), }) + const unpublish = new Unpublish(npm) - unpublish([], err => { + unpublish.exec([], err => { if (err) throw err @@ -104,15 +104,16 @@ t.test('no args --force', t => { t.test('no args --force missing package.json', t => { npm.flatOptions.force = true - const unpublish = requireInject('../../lib/unpublish.js', { + const Unpublish = requireInject('../../lib/unpublish.js', { ...mocks, 'read-package-json': (path, cb) => cb(Object.assign( new Error('ENOENT'), { code: 'ENOENT' } )), }) + const unpublish = new Unpublish(npm) - unpublish([], err => { + unpublish.exec([], err => { t.match( err, /usage instructions/, @@ -125,12 +126,13 @@ t.test('no args --force missing package.json', t => { t.test('no args --force unknown error reading package.json', t => { npm.flatOptions.force = true - const unpublish = requireInject('../../lib/unpublish.js', { + const Unpublish = requireInject('../../lib/unpublish.js', { ...mocks, 'read-package-json': (path, cb) => cb(new Error('ERR')), }) + const unpublish = new Unpublish(npm) - unpublish([], err => { + unpublish.exec([], err => { t.match( err, /ERR/, @@ -141,11 +143,12 @@ t.test('no args --force unknown error reading package.json', t => { }) t.test('no args', t => { - const unpublish = requireInject('../../lib/unpublish.js', { + const Unpublish = requireInject('../../lib/unpublish.js', { ...mocks, }) + const unpublish = new Unpublish(npm) - unpublish([], err => { + unpublish.exec([], err => { t.match( err, /Refusing to delete entire project/, @@ -156,11 +159,12 @@ t.test('no args', t => { }) t.test('too many args', t => { - const unpublish = requireInject('../../lib/unpublish.js', { + const Unpublish = requireInject('../../lib/unpublish.js', { ...mocks, }) + const unpublish = new Unpublish(npm) - unpublish(['a', 'b'], err => { + unpublish.exec(['a', 'b'], err => { t.match( err, /usage instructions/, @@ -206,14 +210,15 @@ t.test('unpublish <pkg>@version', t => { }, } - const unpublish = requireInject('../../lib/unpublish.js', { + const Unpublish = requireInject('../../lib/unpublish.js', { ...mocks, npmlog, libnpmpublish, 'npm-package-arg': npa, }) + const unpublish = new Unpublish(npm) - unpublish(['pkg@1.0.0'], err => { + unpublish.exec(['pkg@1.0.0'], err => { if (err) throw err @@ -235,15 +240,16 @@ t.test('no version found in package.json', t => { npa.resolve = () => '' - const unpublish = requireInject('../../lib/unpublish.js', { + const Unpublish = requireInject('../../lib/unpublish.js', { ...mocks, 'npm-package-arg': npa, 'read-package-json': (path, cb) => cb(null, { name: 'pkg', }), }) + const unpublish = new Unpublish(npm) - unpublish([], err => { + unpublish.exec([], err => { if (err) throw err @@ -259,7 +265,7 @@ t.test('no version found in package.json', t => { t.test('unpublish <pkg> --force no version set', t => { npm.flatOptions.force = true - const unpublish = requireInject('../../lib/unpublish.js', { + const Unpublish = requireInject('../../lib/unpublish.js', { ...mocks, 'npm-package-arg': () => ({ name: 'pkg', @@ -267,8 +273,9 @@ t.test('unpublish <pkg> --force no version set', t => { type: 'tag', }), }) + const unpublish = new Unpublish(npm) - unpublish(['pkg'], err => { + unpublish.exec(['pkg'], err => { if (err) throw err @@ -292,12 +299,13 @@ t.test('silent', t => { npa.resolve = () => '' - const unpublish = requireInject('../../lib/unpublish.js', { + const Unpublish = requireInject('../../lib/unpublish.js', { ...mocks, 'npm-package-arg': npa, }) + const unpublish = new Unpublish(npm) - unpublish(['pkg@1.0.0'], err => { + unpublish.exec(['pkg@1.0.0'], err => { if (err) throw err @@ -312,13 +320,15 @@ t.test('silent', t => { t.test('completion', async t => { const testComp = - async (t, { completion, argv, partialWord, expect, title }) => { - const res = await completion({conf: {argv: {remain: argv}}, partialWord}) + async (t, { unpublish, argv, partialWord, expect, title }) => { + const res = await unpublish.completion( + {conf: {argv: {remain: argv}}, partialWord} + ) t.strictSame(res, expect, title || argv.join(' ')) } t.test('completing with multiple versions from the registry', async t => { - const { completion } = requireInject('../../lib/unpublish.js', { + const Unpublish = requireInject('../../lib/unpublish.js', { ...mocks, libnpmaccess: { async lsPackages () { @@ -341,9 +351,10 @@ t.test('completion', async t => { }, }, }) + const unpublish = new Unpublish(npm) await testComp(t, { - completion, + unpublish, argv: ['npm', 'unpublish'], partialWord: 'pkg', expect: [ @@ -355,7 +366,7 @@ t.test('completion', async t => { }) t.test('no versions retrieved', async t => { - const { completion } = requireInject('../../lib/unpublish.js', { + const Unpublish = requireInject('../../lib/unpublish.js', { ...mocks, libnpmaccess: { async lsPackages () { @@ -374,9 +385,10 @@ t.test('completion', async t => { }, }, }) + const unpublish = new Unpublish(npm) await testComp(t, { - completion, + unpublish, argv: ['npm', 'unpublish'], partialWord: 'pkg', expect: [ @@ -387,7 +399,7 @@ t.test('completion', async t => { }) t.test('packages starting with same letters', async t => { - const { completion } = requireInject('../../lib/unpublish.js', { + const Unpublish = requireInject('../../lib/unpublish.js', { ...mocks, libnpmaccess: { async lsPackages () { @@ -400,9 +412,10 @@ t.test('completion', async t => { }, 'npm-package-arg': require('npm-package-arg'), }) + const unpublish = new Unpublish(npm) await testComp(t, { - completion, + unpublish, argv: ['npm', 'unpublish'], partialWord: 'pkg', expect: [ @@ -414,7 +427,7 @@ t.test('completion', async t => { }) t.test('no packages retrieved', async t => { - const { completion } = requireInject('../../lib/unpublish.js', { + const Unpublish = requireInject('../../lib/unpublish.js', { ...mocks, libnpmaccess: { async lsPackages () { @@ -422,9 +435,10 @@ t.test('completion', async t => { }, }, }) + const unpublish = new Unpublish(npm) await testComp(t, { - completion, + unpublish, argv: ['npm', 'unpublish'], partialWord: 'pkg', expect: [], @@ -433,7 +447,7 @@ t.test('completion', async t => { }) t.test('no pkg name to complete', async t => { - const { completion } = requireInject('../../lib/unpublish.js', { + const Unpublish = requireInject('../../lib/unpublish.js', { ...mocks, libnpmaccess: { async lsPackages () { @@ -444,9 +458,10 @@ t.test('completion', async t => { }, }, }) + const unpublish = new Unpublish(npm) await testComp(t, { - completion, + unpublish, argv: ['npm', 'unpublish'], partialWord: undefined, expect: ['pkg', 'bar'], @@ -455,7 +470,7 @@ t.test('completion', async t => { }) t.test('no pkg names retrieved from user account', async t => { - const { completion } = requireInject('../../lib/unpublish.js', { + const Unpublish = requireInject('../../lib/unpublish.js', { ...mocks, libnpmaccess: { async lsPackages () { @@ -463,9 +478,10 @@ t.test('completion', async t => { }, }, }) + const unpublish = new Unpublish(npm) await testComp(t, { - completion, + unpublish, argv: ['npm', 'unpublish'], partialWord: 'pkg', expect: [], @@ -474,13 +490,14 @@ t.test('completion', async t => { }) t.test('logged out user', async t => { - const { completion } = requireInject('../../lib/unpublish.js', { + const Unpublish = requireInject('../../lib/unpublish.js', { ...mocks, '../../lib/utils/get-identity.js': () => Promise.reject(new Error('ERR')), }) + const unpublish = new Unpublish(npm) await testComp(t, { - completion, + unpublish, argv: ['npm', 'unpublish'], partialWord: 'pkg', expect: [], @@ -488,10 +505,11 @@ t.test('completion', async t => { }) t.test('too many args', async t => { - const { completion } = requireInject('../../lib/unpublish.js', mocks) + const Unpublish = requireInject('../../lib/unpublish.js', mocks) + const unpublish = new Unpublish(npm) await testComp(t, { - completion, + unpublish, argv: ['npm', 'unpublish', 'foo'], partialWord: undefined, expect: [], diff --git a/test/lib/unstar.js b/test/lib/unstar.js index 63b2028a1..3f3487176 100644 --- a/test/lib/unstar.js +++ b/test/lib/unstar.js @@ -4,24 +4,30 @@ const t = require('tap') t.test('unstar', t => { t.plan(3) - const unstar = requireInject('../../lib/unstar.js', { - '../../lib/npm.js': { - config: { - set: (key, value) => { - t.equal(key, 'star.unstar', 'should set unstar config value') - t.equal(value, true, 'should set a truthy value') - }, - }, - commands: { - star: (args, cb) => { - t.deepEqual(args, ['pkg'], 'should forward packages') - cb() - }, + class Star { + constructor (npm) { + this.npm = npm + } + + exec (args, cb) { + t.deepEqual(args, ['pkg'], 'should forward packages') + cb() + } + } + const Unstar = requireInject('../../lib/unstar.js', { + '../../lib/star.js': Star, + }) + + const unstar = new Unstar({ + config: { + set: (key, value) => { + t.equal(key, 'star.unstar', 'should set unstar config value') + t.equal(value, true, 'should set a truthy value') }, }, }) - unstar(['pkg'], err => { + unstar.exec(['pkg'], err => { if (err) throw err }) diff --git a/test/lib/update.js b/test/lib/update.js index 993fbbab5..15195573f 100644 --- a/test/lib/update.js +++ b/test/lib/update.js @@ -16,7 +16,6 @@ const mocks = { '@npmcli/arborist': class { reify () {} }, - '../../lib/npm.js': npm, '../../lib/utils/reify-finish.js': noop, '../../lib/utils/usage.js': () => 'usage instructions', } @@ -47,15 +46,16 @@ t.test('no args', t => { } } - const update = requireInject('../../lib/update.js', { + const Update = requireInject('../../lib/update.js', { ...mocks, - '../../lib/utils/reify-finish.js': (arb) => { + '../../lib/utils/reify-finish.js': (npm, arb) => { t.isLike(arb, Arborist, 'should reify-finish with arborist instance') }, '@npmcli/arborist': Arborist, }) + const update = new Update(npm) - update([], err => { + update.exec([], err => { if (err) throw err }) @@ -80,15 +80,16 @@ t.test('with args', t => { } } - const update = requireInject('../../lib/update.js', { + const Update = requireInject('../../lib/update.js', { ...mocks, - '../../lib/utils/reify-finish.js': (arb) => { + '../../lib/utils/reify-finish.js': (npm, arb) => { t.isLike(arb, Arborist, 'should reify-finish with arborist instance') }, '@npmcli/arborist': Arborist, }) + const update = new Update(npm) - update(['ipt'], err => { + update.exec(['ipt'], err => { if (err) throw err }) @@ -100,7 +101,7 @@ t.test('update --depth=<number>', t => { npm.prefix = '/project/a' npm.flatOptions.depth = 1 - const update = requireInject('../../lib/update.js', { + const Update = requireInject('../../lib/update.js', { ...mocks, npmlog: { warn: (title, msg) => { @@ -113,8 +114,9 @@ t.test('update --depth=<number>', t => { }, }, }) + const update = new Update(npm) - update([], err => { + update.exec([], err => { if (err) throw err }) @@ -150,12 +152,13 @@ t.test('update --global', t => { reify () {} } - const update = requireInject('../../lib/update.js', { + const Update = requireInject('../../lib/update.js', { ...mocks, '@npmcli/arborist': Arborist, }) + const update = new Update(npm) - update([], err => { + update.exec([], err => { if (err) throw err }) diff --git a/test/lib/utils/audit-error.js b/test/lib/utils/audit-error.js index cc5f4c006..ea7c84373 100644 --- a/test/lib/utils/audit-error.js +++ b/test/lib/utils/audit-error.js @@ -12,7 +12,6 @@ const npm = { const OUTPUT = [] const output = (...msg) => OUTPUT.push(msg) const auditError = requireInject('../../../lib/utils/audit-error.js', { - '../../../lib/npm.js': npm, '../../../lib/utils/output.js': output, }) @@ -25,7 +24,7 @@ t.afterEach(cb => { t.test('no error, not audit command', t => { npm.command = 'install' - t.equal(auditError({}), false, 'no error') + t.equal(auditError(npm, {}), false, 'no error') t.strictSame(OUTPUT, [], 'no output') t.strictSame(LOGS, [], 'no warnings') t.end() @@ -33,7 +32,7 @@ t.test('no error, not audit command', t => { t.test('error, not audit command', t => { npm.command = 'install' - t.equal(auditError({ + t.equal(auditError(npm, { error: { message: 'message', body: Buffer.from('body'), @@ -53,7 +52,7 @@ t.test('error, not audit command', t => { t.test('error, audit command, not json', t => { npm.command = 'audit' npm.flatOptions.json = false - t.throws(() => auditError({ + t.throws(() => auditError(npm, { error: { message: 'message', body: Buffer.from('body'), @@ -74,7 +73,7 @@ t.test('error, audit command, not json', t => { t.test('error, audit command, json', t => { npm.command = 'audit' npm.flatOptions.json = true - t.throws(() => auditError({ + t.throws(() => auditError(npm, { error: { message: 'message', body: { response: 'body' }, diff --git a/test/lib/utils/completion/installed-deep.js b/test/lib/utils/completion/installed-deep.js index bd61ab428..0e80a5a19 100644 --- a/test/lib/utils/completion/installed-deep.js +++ b/test/lib/utils/completion/installed-deep.js @@ -12,22 +12,21 @@ const _flatOptions = { }, } const p = '../../../../lib/utils/completion/installed-deep.js' -const installedDeep = requireInject(p, { - '../../../../lib/npm.js': { - flatOptions: _flatOptions, - get prefix () { - return _flatOptions.prefix - }, - get globalDir () { - return globalDir - }, - config: { - get (key) { - return _flatOptions[key] - }, +const installedDeep = requireInject(p) +const npm = { + flatOptions: _flatOptions, + get prefix () { + return _flatOptions.prefix + }, + get globalDir () { + return globalDir + }, + config: { + get (key) { + return _flatOptions[key] }, }, -}) +} const fixture = { 'package.json': JSON.stringify({ @@ -154,7 +153,7 @@ test('get list of package names', async t => { prefix = resolve(fix, 'local') globalDir = resolve(fix, 'global/node_modules') - const res = await installedDeep(null) + const res = await installedDeep(npm, null) t.deepEqual( res, [ @@ -181,7 +180,7 @@ test('get list of package names as global', async t => { _flatOptions.global = true - const res = await installedDeep(null) + const res = await installedDeep(npm, null) t.deepEqual( res, [ @@ -206,7 +205,7 @@ test('limit depth', async t => { _flatOptions.depth = 0 - const res = await installedDeep(null) + const res = await installedDeep(npm, null) t.deepEqual( res, [ @@ -235,7 +234,7 @@ test('limit depth as global', async t => { _flatOptions.global = true _flatOptions.depth = 0 - const res = await installedDeep(null) + const res = await installedDeep(npm, null) t.deepEqual( res, [ diff --git a/test/lib/utils/completion/installed-shallow.js b/test/lib/utils/completion/installed-shallow.js index 1da68810b..1067a50ac 100644 --- a/test/lib/utils/completion/installed-shallow.js +++ b/test/lib/utils/completion/installed-shallow.js @@ -5,9 +5,7 @@ const t = require('tap') const { resolve } = require('path') const p = '../../../../lib/utils/completion/installed-shallow.js' -const installed = requireInject(p, { - '../../../../lib/npm.js': npm, -}) +const installed = requireInject(p) t.test('global not set, include globals with -g', async t => { const dir = t.testdir({ @@ -32,7 +30,7 @@ t.test('global not set, include globals with -g', async t => { npm.localDir = resolve(dir, 'local/node_modules') flatOptions.global = false const opt = { conf: { argv: { remain: [] } } } - const res = await installed(opt) + const res = await installed(npm, opt) t.strictSame(res.sort(), [ '@scope/y -g', 'x -g', @@ -65,7 +63,7 @@ t.test('global set, include globals and not locals', async t => { npm.localDir = resolve(dir, 'local/node_modules') flatOptions.global = true const opt = { conf: { argv: { remain: [] } } } - const res = await installed(opt) + const res = await installed(npm, opt) t.strictSame(res.sort(), [ '@scope/y', 'x', @@ -96,7 +94,7 @@ t.test('more than 3 items in argv, skip it', async t => { npm.localDir = resolve(dir, 'local/node_modules') flatOptions.global = false const opt = { conf: { argv: { remain: [1, 2, 3, 4, 5, 6] } } } - const res = await installed(opt) + const res = await installed(npm, opt) t.strictSame(res, null) t.end() }) diff --git a/test/lib/utils/get-identity.js b/test/lib/utils/get-identity.js index 8a4de8835..cc713b337 100644 --- a/test/lib/utils/get-identity.js +++ b/test/lib/utils/get-identity.js @@ -3,12 +3,10 @@ const requireInject = require('require-inject') test('throws ENOREGISTRY when no registry option is provided', async (t) => { t.plan(2) - const getIdentity = requireInject('../../../lib/utils/get-identity.js', { - '../../../lib/npm.js': {}, - }) + const getIdentity = requireInject('../../../lib/utils/get-identity.js') try { - await getIdentity() + await getIdentity({}) } catch (err) { t.equal(err.code, 'ENOREGISTRY', 'assigns the appropriate error code') t.equal(err.message, 'No registry specified.', 'returns the correct error message') @@ -18,17 +16,16 @@ test('throws ENOREGISTRY when no registry option is provided', async (t) => { test('returns username from uri when provided', async (t) => { t.plan(1) - const getIdentity = requireInject('../../../lib/utils/get-identity.js', { - '../../../lib/npm.js': { - config: { - getCredentialsByURI: () => { - return { username: 'foo' } - }, + const getIdentity = requireInject('../../../lib/utils/get-identity.js') + const npm = { + config: { + getCredentialsByURI: () => { + return { username: 'foo' } }, }, - }) + } - const identity = await getIdentity({ registry: 'https://registry.npmjs.org' }) + const identity = await getIdentity(npm, { registry: 'https://registry.npmjs.org' }) t.equal(identity, 'foo', 'returns username from uri') }) @@ -41,11 +38,6 @@ test('calls registry whoami when token is provided', async (t) => { } const getIdentity = requireInject('../../../lib/utils/get-identity.js', { - '../../../lib/npm.js': { - config: { - getCredentialsByURI: () => options, - }, - }, 'npm-registry-fetch': { json: (path, opts) => { t.equal(path, '/-/whoami', 'calls whoami') @@ -54,8 +46,13 @@ test('calls registry whoami when token is provided', async (t) => { }, }, }) + const npm = { + config: { + getCredentialsByURI: () => options, + }, + } - const identity = await getIdentity(options) + const identity = await getIdentity(npm, options) t.equal(identity, 'foo', 'fetched username from registry') }) @@ -68,11 +65,6 @@ test('throws ENEEDAUTH when response does not include a username', async (t) => } const getIdentity = requireInject('../../../lib/utils/get-identity.js', { - '../../../lib/npm.js': { - config: { - getCredentialsByURI: () => options, - }, - }, 'npm-registry-fetch': { json: (path, opts) => { t.equal(path, '/-/whoami', 'calls whoami') @@ -81,9 +73,14 @@ test('throws ENEEDAUTH when response does not include a username', async (t) => }, }, }) + const npm = { + config: { + getCredentialsByURI: () => options, + }, + } try { - await getIdentity(options) + await getIdentity(npm, options) } catch (err) { t.equal(err.code, 'ENEEDAUTH', 'throws correct error code') } @@ -92,15 +89,15 @@ test('throws ENEEDAUTH when response does not include a username', async (t) => test('throws ENEEDAUTH when neither username nor token is configured', async (t) => { t.plan(1) const getIdentity = requireInject('../../../lib/utils/get-identity.js', { - '../../../lib/npm.js': { - config: { - getCredentialsByURI: () => ({}), - }, - }, }) + const npm = { + config: { + getCredentialsByURI: () => ({}), + }, + } try { - await getIdentity({ registry: 'https://registry.npmjs.org' }) + await getIdentity(npm, { registry: 'https://registry.npmjs.org' }) } catch (err) { t.equal(err.code, 'ENEEDAUTH', 'throws correct error code') } diff --git a/test/lib/utils/lifecycle-cmd.js b/test/lib/utils/lifecycle-cmd.js index 3928c1b26..2f1f693f2 100644 --- a/test/lib/utils/lifecycle-cmd.js +++ b/test/lib/utils/lifecycle-cmd.js @@ -1,13 +1,19 @@ const t = require('tap') -const lifecycleCmd = require('../../../lib/utils/lifecycle-cmd.js') +const LifecycleCmd = require('../../../lib/utils/lifecycle-cmd.js') +let runArgs = null const npm = { commands: { - 'run-script': (args, cb) => cb(null, 'called npm.commands.run'), + 'run-script': (args, cb) => { + runArgs = args + cb(null, 'called npm.commands.run') + }, }, } t.test('create a lifecycle command', t => { - const cmd = lifecycleCmd(npm, 'asdf') - cmd(['some', 'args'], (er, result) => { + const cmd = new LifecycleCmd(npm, 'test-stage') + t.match(cmd.usage, /test-stage/) + cmd.exec(['some', 'args'], (er, result) => { + t.same(runArgs, ['test-stage', 'some', 'args']) t.strictSame(result, 'called npm.commands.run') t.end() }) diff --git a/test/lib/utils/npm-usage.js b/test/lib/utils/npm-usage.js index 72504b90c..dbbde947c 100644 --- a/test/lib/utils/npm-usage.js +++ b/test/lib/utils/npm-usage.js @@ -1,127 +1,121 @@ const t = require('tap') -const deref = require('../../../lib/utils/deref-command.js') -const npm = { - argv: [], - deref, - config: { - _options: { - viewer: null, - long: false, - userconfig: '/some/config/file/.npmrc', - }, - get: k => { - if (npm.config._options[k] === undefined) - throw new Error('unknown config') - return npm.config._options[k] - }, - set: (k, v) => { - npm.config._options[k] = v - }, - }, - log: {}, - version: '{VERSION}', -} - const OUTPUT = [] const output = (...msg) => OUTPUT.push(msg) - -const { dirname } = require('path') -const basedir = dirname(dirname(dirname(__dirname))) -t.cleanSnapshot = str => str.split(basedir).join('{BASEDIR}') - .split(require('../../../package.json').version).join('{VERSION}') - const requireInject = require('require-inject') const usage = requireInject('../../../lib/utils/npm-usage.js', { - '../../../lib/npm.js': npm, '../../../lib/utils/output.js': output, }) +const npm = requireInject('../../../lib/npm.js') -t.test('basic usage', t => { - usage() - t.equal(OUTPUT.length, 1) - t.equal(OUTPUT[0].length, 1) - t.matchSnapshot(OUTPUT[0][0]) - OUTPUT.length = 0 - t.end() -}) - -t.test('with browser', t => { - npm.config.set('viewer', 'browser') - usage() - t.equal(OUTPUT.length, 1) - t.equal(OUTPUT[0].length, 1) - t.matchSnapshot(OUTPUT[0][0]) - OUTPUT.length = 0 - npm.config.set('viewer', null) - t.end() -}) +t.test('usage', t => { + t.afterEach((cb) => { + npm.config.set('viewer', null) + npm.config.set('long', false) + npm.config.set('userconfig', '/some/config/file/.npmrc') + cb() + }) + const { dirname } = require('path') + const basedir = dirname(dirname(dirname(__dirname))) + t.cleanSnapshot = str => str.split(basedir).join('{BASEDIR}') + .split(require('../../../package.json').version).join('{VERSION}') -t.test('with long', t => { - npm.config.set('long', true) - usage() - t.equal(OUTPUT.length, 1) - t.equal(OUTPUT[0].length, 1) - t.matchSnapshot(OUTPUT[0][0]) - OUTPUT.length = 0 - npm.config.set('long', false) - t.end() -}) + npm.load(err => { + if (err) + throw err -t.test('did you mean?', t => { - npm.argv.push('unistnall') - usage() - t.equal(OUTPUT.length, 2) - t.equal(OUTPUT[0].length, 1) - t.equal(OUTPUT[1].length, 1) - t.matchSnapshot(OUTPUT[0][0]) - t.matchSnapshot(OUTPUT[1][0]) - OUTPUT.length = 0 - npm.argv.length = 0 - t.end() -}) + npm.config.set('viewer', null) + npm.config.set('long', false) + npm.config.set('userconfig', '/some/config/file/.npmrc') -t.test('did you mean?', t => { - npm.argv.push('unistnall') - const { exitCode } = process - t.teardown(() => { - if (t.passing()) - process.exitCode = exitCode - }) - // make sure it fails when invalid - usage(false) - t.equal(process.exitCode, 1) - OUTPUT.length = 0 - npm.argv.length = 0 - t.end() -}) + t.test('basic usage', t => { + usage(npm) + t.equal(OUTPUT.length, 1) + t.equal(OUTPUT[0].length, 1) + t.matchSnapshot(OUTPUT[0][0]) + OUTPUT.length = 0 + t.end() + }) -t.test('set process.stdout.columns', t => { - const { columns } = process.stdout - t.teardown(() => { - Object.defineProperty(process.stdout, 'columns', { - value: columns, - enumerable: true, - configurable: true, - writable: true, + t.test('with browser', t => { + npm.config.set('viewer', 'browser') + usage(npm) + t.equal(OUTPUT.length, 1) + t.equal(OUTPUT[0].length, 1) + t.matchSnapshot(OUTPUT[0][0]) + OUTPUT.length = 0 + npm.config.set('viewer', null) + t.end() }) - }) - const cases = [0, 90] - for (const cols of cases) { - t.test(`columns=${cols}`, t => { - Object.defineProperty(process.stdout, 'columns', { - value: cols, - enumerable: true, - configurable: true, - writable: true, - }) - usage() + + t.test('with long', t => { + npm.config.set('long', true) + usage(npm) t.equal(OUTPUT.length, 1) t.equal(OUTPUT[0].length, 1) t.matchSnapshot(OUTPUT[0][0]) OUTPUT.length = 0 + npm.config.set('long', false) + t.end() + }) + + t.test('did you mean?', t => { + npm.argv.push('unistnall') + usage(npm) + t.equal(OUTPUT.length, 2) + t.equal(OUTPUT[0].length, 1) + t.equal(OUTPUT[1].length, 1) + t.matchSnapshot(OUTPUT[0][0]) + t.matchSnapshot(OUTPUT[1][0]) + OUTPUT.length = 0 + npm.argv.length = 0 t.end() }) - } - t.end() + + t.test('did you mean?', t => { + npm.argv.push('unistnall') + const { exitCode } = process + t.teardown(() => { + if (t.passing()) + process.exitCode = exitCode + }) + // make sure it fails when invalid + usage(npm, false) + t.equal(process.exitCode, 1) + OUTPUT.length = 0 + npm.argv.length = 0 + t.end() + }) + + t.test('set process.stdout.columns', t => { + const { columns } = process.stdout + t.teardown(() => { + Object.defineProperty(process.stdout, 'columns', { + value: columns, + enumerable: true, + configurable: true, + writable: true, + }) + }) + const cases = [0, 90] + for (const cols of cases) { + t.test(`columns=${cols}`, t => { + Object.defineProperty(process.stdout, 'columns', { + value: cols, + enumerable: true, + configurable: true, + writable: true, + }) + usage(npm) + t.equal(OUTPUT.length, 1) + t.equal(OUTPUT[0].length, 1) + t.matchSnapshot(OUTPUT[0][0]) + OUTPUT.length = 0 + t.end() + }) + } + t.end() + }) + t.end() + }) }) diff --git a/test/lib/utils/open-url.js b/test/lib/utils/open-url.js index ce1783dad..e8ab8f15a 100644 --- a/test/lib/utils/open-url.js +++ b/test/lib/utils/open-url.js @@ -27,59 +27,49 @@ const opener = (url, opts, cb) => { } const openUrl = requireInject('../../../lib/utils/open-url.js', { - '../../../lib/npm.js': npm, '../../../lib/utils/output.js': output, opener, }) -test('opens a url', (t) => { +test('opens a url', async (t) => { t.teardown(() => { openerUrl = null openerOpts = null OUTPUT.length = 0 }) - openUrl('https://www.npmjs.com', 'npm home', (err) => { - if (err) - throw err - - t.equal(openerUrl, 'https://www.npmjs.com', 'opened the given url') - t.same(openerOpts, { command: null }, 'passed command as null (the default)') - t.same(OUTPUT, [], 'printed no output') - t.done() - }) + await openUrl(npm, 'https://www.npmjs.com', 'npm home') + t.equal(openerUrl, 'https://www.npmjs.com', 'opened the given url') + t.same(openerOpts, { command: null }, 'passed command as null (the default)') + t.same(OUTPUT, [], 'printed no output') }) -test('returns error for non-https and non-file url', (t) => { +test('returns error for non-https and non-file url', async (t) => { t.teardown(() => { openerUrl = null openerOpts = null OUTPUT.length = 0 }) - openUrl('ftp://www.npmjs.com', 'npm home', (err) => { - t.match(err, /Invalid URL/, 'got the correct error') - t.equal(openerUrl, null, 'did not open') - t.same(openerOpts, null, 'did not open') - t.same(OUTPUT, [], 'printed no output') - t.done() - }) + t.rejects(openUrl(npm, 'ftp://www.npmjs.com', 'npm home'), /Invalid URL/, 'got the correct error') + t.equal(openerUrl, null, 'did not open') + t.same(openerOpts, null, 'did not open') + t.same(OUTPUT, [], 'printed no output') + t.done() }) -test('returns error for non-parseable url', (t) => { +test('returns error for non-parseable url', async (t) => { t.teardown(() => { openerUrl = null openerOpts = null OUTPUT.length = 0 }) - openUrl('git+ssh://user@host:repo.git', 'npm home', (err) => { - t.match(err, /Invalid URL/, 'got the correct error') - t.equal(openerUrl, null, 'did not open') - t.same(openerOpts, null, 'did not open') - t.same(OUTPUT, [], 'printed no output') - t.done() - }) + t.rejects(openUrl(npm, 'git+ssh://user@host:repo.git', 'npm home'), /Invalid URL/, 'got the correct error') + t.equal(openerUrl, null, 'did not open') + t.same(openerOpts, null, 'did not open') + t.same(OUTPUT, [], 'printed no output') + t.done() }) -test('opens a url with the given browser', (t) => { +test('opens a url with the given browser', async (t) => { npm.config.set('browser', 'chrome') t.teardown(() => { openerUrl = null @@ -87,18 +77,14 @@ test('opens a url with the given browser', (t) => { OUTPUT.length = 0 npm.config.set('browser', true) }) - openUrl('https://www.npmjs.com', 'npm home', (err) => { - if (err) - throw err - - t.equal(openerUrl, 'https://www.npmjs.com', 'opened the given url') - t.same(openerOpts, { command: 'chrome' }, 'passed the given browser as command') - t.same(OUTPUT, [], 'printed no output') - t.done() - }) + await openUrl(npm, 'https://www.npmjs.com', 'npm home') + t.equal(openerUrl, 'https://www.npmjs.com', 'opened the given url') + t.same(openerOpts, { command: 'chrome' }, 'passed the given browser as command') + t.same(OUTPUT, [], 'printed no output') + t.done() }) -test('prints where to go when browser is disabled', (t) => { +test('prints where to go when browser is disabled', async (t) => { npm.config.set('browser', false) t.teardown(() => { openerUrl = null @@ -106,20 +92,16 @@ test('prints where to go when browser is disabled', (t) => { OUTPUT.length = 0 npm.config.set('browser', true) }) - openUrl('https://www.npmjs.com', 'npm home', (err) => { - if (err) - throw err - - t.equal(openerUrl, null, 'did not open') - t.same(openerOpts, null, 'did not open') - t.equal(OUTPUT.length, 1, 'got one logged message') - t.equal(OUTPUT[0].length, 1, 'logged message had one value') - t.matchSnapshot(OUTPUT[0][0], 'printed expected message') - t.done() - }) + await openUrl(npm, 'https://www.npmjs.com', 'npm home') + t.equal(openerUrl, null, 'did not open') + t.same(openerOpts, null, 'did not open') + t.equal(OUTPUT.length, 1, 'got one logged message') + t.equal(OUTPUT[0].length, 1, 'logged message had one value') + t.matchSnapshot(OUTPUT[0][0], 'printed expected message') + t.done() }) -test('prints where to go when browser is disabled and json is enabled', (t) => { +test('prints where to go when browser is disabled and json is enabled', async (t) => { npm.config.set('browser', false) npm.config.set('json', true) t.teardown(() => { @@ -129,20 +111,16 @@ test('prints where to go when browser is disabled and json is enabled', (t) => { npm.config.set('browser', true) npm.config.set('json', false) }) - openUrl('https://www.npmjs.com', 'npm home', (err) => { - if (err) - throw err - - t.equal(openerUrl, null, 'did not open') - t.same(openerOpts, null, 'did not open') - t.equal(OUTPUT.length, 1, 'got one logged message') - t.equal(OUTPUT[0].length, 1, 'logged message had one value') - t.matchSnapshot(OUTPUT[0][0], 'printed expected message') - t.done() - }) + await openUrl(npm, 'https://www.npmjs.com', 'npm home') + t.equal(openerUrl, null, 'did not open') + t.same(openerOpts, null, 'did not open') + t.equal(OUTPUT.length, 1, 'got one logged message') + t.equal(OUTPUT[0].length, 1, 'logged message had one value') + t.matchSnapshot(OUTPUT[0][0], 'printed expected message') + t.done() }) -test('prints where to go when given browser does not exist', (t) => { +test('prints where to go when given browser does not exist', async (t) => { npm.config.set('browser', 'firefox') openerResult = Object.assign(new Error('failed'), { code: 'ENOENT' }) t.teardown(() => { @@ -151,15 +129,24 @@ test('prints where to go when given browser does not exist', (t) => { OUTPUT.length = 0 npm.config.set('browser', true) }) - openUrl('https://www.npmjs.com', 'npm home', (err) => { - if (err) - throw err + await openUrl(npm, 'https://www.npmjs.com', 'npm home') + t.equal(openerUrl, 'https://www.npmjs.com', 'tried to open the correct url') + t.same(openerOpts, { command: 'firefox' }, 'tried to use the correct browser') + t.equal(OUTPUT.length, 1, 'got one logged message') + t.equal(OUTPUT[0].length, 1, 'logged message had one value') + t.matchSnapshot(OUTPUT[0][0], 'printed expected message') + t.done() +}) - t.equal(openerUrl, 'https://www.npmjs.com', 'tried to open the correct url') - t.same(openerOpts, { command: 'firefox' }, 'tried to use the correct browser') - t.equal(OUTPUT.length, 1, 'got one logged message') - t.equal(OUTPUT[0].length, 1, 'logged message had one value') - t.matchSnapshot(OUTPUT[0][0], 'printed expected message') - t.done() +test('handles unknown opener error', async (t) => { + npm.config.set('browser', 'firefox') + openerResult = Object.assign(new Error('failed'), { code: 'ENOBRIAN' }) + t.teardown(() => { + openerUrl = null + openerOpts = null + OUTPUT.length = 0 + npm.config.set('browser', true) }) + t.rejects(openUrl(npm, 'https://www.npmjs.com', 'npm home'), 'failed', 'got the correct error') + t.done() }) diff --git a/test/lib/utils/read-local-package.js b/test/lib/utils/read-local-package.js index 33a408eb5..9ae21f7d6 100644 --- a/test/lib/utils/read-local-package.js +++ b/test/lib/utils/read-local-package.js @@ -10,11 +10,10 @@ const _flatOptions = { }, } -const readLocalPackageName = requireInject('../../../lib/utils/read-local-package.js', { - '../../../lib/npm.js': { - flatOptions: _flatOptions, - }, -}) +const readLocalPackageName = requireInject('../../../lib/utils/read-local-package.js') +const npm = { + flatOptions: _flatOptions, +} test('read local package.json', async (t) => { prefix = t.testdir({ @@ -23,7 +22,7 @@ test('read local package.json', async (t) => { version: '1.0.0', }), }) - const packageName = await readLocalPackageName() + const packageName = await readLocalPackageName(npm) t.equal( packageName, 'my-local-package', @@ -38,7 +37,7 @@ test('read local scoped-package.json', async (t) => { version: '1.0.0', }), }) - const packageName = await readLocalPackageName() + const packageName = await readLocalPackageName(npm) t.equal( packageName, '@my-scope/my-local-package', @@ -49,7 +48,7 @@ test('read local scoped-package.json', async (t) => { test('read using --global', async (t) => { prefix = t.testdir({}) _flatOptions.global = true - const packageName = await readLocalPackageName() + const packageName = await readLocalPackageName(npm) t.equal( packageName, undefined, diff --git a/test/lib/utils/reify-finish.js b/test/lib/utils/reify-finish.js index 39277f21a..7ff5146a6 100644 --- a/test/lib/utils/reify-finish.js +++ b/test/lib/utils/reify-finish.js @@ -32,13 +32,12 @@ const fs = { const reifyFinish = requireInject('../../../lib/utils/reify-finish.js', { fs, - '../../../lib/npm.js': npm, '../../../lib/utils/reify-output.js': reifyOutput, }) t.test('should not write if not global', async t => { expectWrite = false - await reifyFinish({ + await reifyFinish(npm, { options: { global: false }, actualTree: {}, }) @@ -46,7 +45,7 @@ t.test('should not write if not global', async t => { t.test('should not write if no global npm module', async t => { expectWrite = false - await reifyFinish({ + await reifyFinish(npm, { options: { global: true }, actualTree: { inventory: new Map(), @@ -56,7 +55,7 @@ t.test('should not write if no global npm module', async t => { t.test('should not write if builtin conf had load error', async t => { expectWrite = false - await reifyFinish({ + await reifyFinish(npm, { options: { global: true }, actualTree: { inventory: new Map([['node_modules/npm', {}]]), @@ -68,7 +67,7 @@ t.test('should write if everything above passes', async t => { expectWrite = true delete builtinConfMock.loadError const path = t.testdir() - await reifyFinish({ + await reifyFinish(npm, { options: { global: true }, actualTree: { inventory: new Map([['node_modules/npm', {path}]]), diff --git a/test/lib/utils/reify-output.js b/test/lib/utils/reify-output.js index f88f072e1..e41eabcb8 100644 --- a/test/lib/utils/reify-output.js +++ b/test/lib/utils/reify-output.js @@ -9,7 +9,7 @@ t.cleanSnapshot = str => str.replace(/in [0-9]+m?s/g, 'in {TIME}') const settings = { fund: true, } -const npmock = { +const npm = { started: Date.now(), flatOptions: settings, } @@ -17,7 +17,6 @@ const getReifyOutput = tester => requireInject( '../../../lib/utils/reify-output.js', { - '../../../lib/npm.js': npmock, '../../../lib/utils/output.js': tester, } ) @@ -32,7 +31,7 @@ t.test('missing info', (t) => { ) ) - reifyOutput({ + reifyOutput(npm, { actualTree: { children: [], }, @@ -52,7 +51,7 @@ t.test('even more missing info', t => { ) ) - reifyOutput({ + reifyOutput(npm, { actualTree: { children: [], }, @@ -73,7 +72,7 @@ t.test('single package', (t) => { } ) - reifyOutput({ + reifyOutput(npm, { // a report with an error is the same as no report at all, if // the command is not 'audit' auditReport: { @@ -118,7 +117,7 @@ t.test('no message when funding config is false', (t) => { } ) - reifyOutput({ + reifyOutput(npm, { actualTree: { name: 'foo', package: { @@ -160,7 +159,7 @@ t.test('print appropriate message for many packages', (t) => { } ) - reifyOutput({ + reifyOutput(npm, { actualTree: { name: 'foo', package: { @@ -212,7 +211,7 @@ t.test('no output when silent', t => { }) t.teardown(() => log.level = 'warn') log.level = 'silent' - reifyOutput({ + reifyOutput(npm, { actualTree: { inventory: { size: 999 }, children: [] }, auditReport: { toJSON: () => { @@ -243,7 +242,7 @@ t.test('packages changed message', t => { // return a test function that builds up the mock and snapshots output const testCase = (t, added, removed, changed, audited, json, command) => { settings.json = json - npmock.command = command + npm.command = command const mock = { actualTree: { inventory: { size: audited, has: () => true }, @@ -276,7 +275,7 @@ t.test('packages changed message', t => { mock.diff.children.push({ action: 'CHANGE', actual, ideal }) } output.length = 0 - reifyOutput(mock) + reifyOutput(npm, mock) t.matchSnapshot(output.join('\n'), JSON.stringify({ added, removed, @@ -316,7 +315,7 @@ t.test('added packages should be looked up within returned tree', t => { out => t.matchSnapshot(out) ) - reifyOutput({ + reifyOutput(npm, { actualTree: { name: 'foo', inventory: { @@ -337,7 +336,7 @@ t.test('added packages should be looked up within returned tree', t => { out => t.matchSnapshot(out) ) - reifyOutput({ + reifyOutput(npm, { actualTree: { name: 'foo', inventory: { diff --git a/test/lib/version.js b/test/lib/version.js index a69953bb8..e0e07f517 100644 --- a/test/lib/version.js +++ b/test/lib/version.js @@ -14,7 +14,6 @@ const npm = { } const mocks = { libnpmversion: noop, - '../../lib/npm.js': npm, '../../lib/utils/output.js': (...msg) => { for (const m of msg) result.push(m) @@ -22,7 +21,8 @@ const mocks = { '../../lib/utils/usage.js': () => 'usage instructions', } -const version = requireInject('../../lib/version.js', mocks) +const Version = requireInject('../../lib/version.js', mocks) +const version = new Version(npm) const _processVersions = process.versions t.afterEach(cb => { @@ -43,7 +43,7 @@ t.test('no args', t => { npm.prefix = prefix Object.defineProperty(process, 'versions', { value: { node: '1.0.0' } }) - version([], err => { + version.exec([], err => { if (err) throw err @@ -62,7 +62,7 @@ t.test('no args', t => { }) t.test('too many args', t => { - version(['foo', 'bar'], err => { + version.exec(['foo', 'bar'], err => { t.match( err, 'usage instructions', @@ -74,10 +74,8 @@ t.test('too many args', t => { }) t.test('completion', async t => { - const { completion } = version - const testComp = async (argv, expect) => { - const res = await completion({ conf: { argv: { remain: argv } } }) + const res = await version.completion({ conf: { argv: { remain: argv } } }) t.strictSame(res, expect, argv.join(' ')) } @@ -100,7 +98,7 @@ t.test('failure reading package.json', t => { const prefix = t.testdir({}) npm.prefix = prefix - version([], err => { + version.exec([], err => { if (err) throw err @@ -123,7 +121,7 @@ t.test('--json option', t => { npm.prefix = prefix Object.defineProperty(process, 'versions', { value: {} }) - version([], err => { + version.exec([], err => { if (err) throw err t.deepEqual( @@ -136,7 +134,7 @@ t.test('--json option', t => { }) t.test('with one arg', t => { - const version = requireInject('../../lib/version.js', { + const Version = requireInject('../../lib/version.js', { ...mocks, libnpmversion: (arg, opts) => { t.equal(arg, 'major', 'should forward expected value') @@ -152,8 +150,9 @@ t.test('with one arg', t => { return '4.0.0' }, }) + const version = new Version(npm) - version(['major'], err => { + version.exec(['major'], err => { if (err) throw err t.same(result, ['v4.0.0'], 'outputs the new version prefixed by the tagVersionPrefix') diff --git a/test/lib/view.js b/test/lib/view.js index 9419ab7ec..1363a5b9f 100644 --- a/test/lib/view.js +++ b/test/lib/view.js @@ -238,98 +238,98 @@ const packument = (nv, opts) => { t.beforeEach(cleanLogs) t.test('should log package info', t => { - const view = requireInject('../../lib/view.js', { - '../../lib/npm.js': { - flatOptions: { - global: false, - }, - }, + const View = requireInject('../../lib/view.js', { pacote: { packument, }, }) - - const viewJson = requireInject('../../lib/view.js', { - '../../lib/npm.js': { - flatOptions: { - json: true, - }, + const view = new View({ + flatOptions: { + global: false, }, + }) + + const ViewJson = requireInject('../../lib/view.js', { pacote: { packument, }, }) - - const viewUnicode = requireInject('../../lib/view.js', { - '../../lib/npm.js': { - flatOptions: { - global: false, - unicode: true, - }, + const viewJson = new ViewJson({ + flatOptions: { + json: true, }, + }) + + const ViewUnicode = requireInject('../../lib/view.js', { pacote: { packument, }, }) + const viewUnicode = new ViewUnicode({ + flatOptions: { + global: false, + unicode: true, + }, + }) t.test('package with license, bugs, repository and other fields', t => { - view(['green@1.0.0'], () => { + view.exec(['green@1.0.0'], () => { t.matchSnapshot(logs) t.end() }) }) t.test('package with more than 25 deps', t => { - view(['black@1.0.0'], () => { + view.exec(['black@1.0.0'], () => { t.matchSnapshot(logs) t.end() }) }) t.test('package with maintainers info as object', t => { - view(['pink@1.0.0'], () => { + view.exec(['pink@1.0.0'], () => { t.matchSnapshot(logs) t.end() }) }) t.test('package with homepage', t => { - view(['orange@1.0.0'], () => { + view.exec(['orange@1.0.0'], () => { t.matchSnapshot(logs) t.end() }) }) t.test('package with no versions', t => { - view(['brown'], () => { + view.exec(['brown'], () => { t.equals(logs, '', 'no info to display') t.end() }) }) t.test('package with no repo or homepage', t => { - view(['blue@1.0.0'], () => { + view.exec(['blue@1.0.0'], () => { t.matchSnapshot(logs) t.end() }) }) t.test('package with no modified time', t => { - viewUnicode(['cyan@1.0.0'], () => { + viewUnicode.exec(['cyan@1.0.0'], () => { t.matchSnapshot(logs) t.end() }) }) t.test('package with --json and semver range', t => { - viewJson(['cyan@^1.0.0'], () => { + viewJson.exec(['cyan@^1.0.0'], () => { t.matchSnapshot(logs) t.end() }) }) t.test('package with --json and no versions', t => { - viewJson(['brown'], () => { + viewJson.exec(['brown'], () => { t.equals(logs, '', 'no info to display') t.end() }) @@ -346,28 +346,28 @@ t.test('should log info of package in current working dir', t => { }, null, 2), }) - const view = requireInject('../../lib/view.js', { - '../../lib/npm.js': { - prefix: testDir, - flatOptions: { - defaultTag: '1.0.0', - global: false, - }, - }, + const View = requireInject('../../lib/view.js', { pacote: { packument, }, }) + const view = new View({ + prefix: testDir, + flatOptions: { + defaultTag: '1.0.0', + global: false, + }, + }) t.test('specific version', t => { - view(['.@1.0.0'], () => { + view.exec(['.@1.0.0'], () => { t.matchSnapshot(logs) t.end() }) }) t.test('non-specific version', t => { - view(['.'], () => { + view.exec(['.'], () => { t.matchSnapshot(logs) t.end() }) @@ -377,87 +377,87 @@ t.test('should log info of package in current working dir', t => { }) t.test('should log info by field name', t => { - const viewJson = requireInject('../../lib/view.js', { - '../../lib/npm.js': { - flatOptions: { - json: true, - global: false, - }, - }, + const ViewJson = requireInject('../../lib/view.js', { pacote: { packument, }, }) - - const view = requireInject('../../lib/view.js', { - '../../lib/npm.js': { - flatOptions: { - global: false, - }, + const viewJson = new ViewJson({ + flatOptions: { + json: true, + global: false, }, + }) + + const View = requireInject('../../lib/view.js', { pacote: { packument, }, }) + const view = new View({ + flatOptions: { + global: false, + }, + }) t.test('readme', t => { - view(['yellow@1.0.0', 'readme'], () => { + view.exec(['yellow@1.0.0', 'readme'], () => { t.matchSnapshot(logs) t.end() }) }) t.test('several fields', t => { - viewJson(['yellow@1.0.0', 'name', 'version', 'foo[bar]'], () => { + viewJson.exec(['yellow@1.0.0', 'name', 'version', 'foo[bar]'], () => { t.matchSnapshot(logs) t.end() }) }) t.test('several fields with several versions', t => { - view(['yellow@1.x.x', 'author'], () => { + view.exec(['yellow@1.x.x', 'author'], () => { t.matchSnapshot(logs) t.end() }) }) t.test('nested field with brackets', t => { - viewJson(['orange@1.0.0', 'dist[shasum]'], () => { + viewJson.exec(['orange@1.0.0', 'dist[shasum]'], () => { t.matchSnapshot(logs) t.end() }) }) t.test('maintainers with email', t => { - viewJson(['yellow@1.0.0', 'maintainers', 'name'], () => { + viewJson.exec(['yellow@1.0.0', 'maintainers', 'name'], () => { t.matchSnapshot(logs) t.end() }) }) t.test('maintainers with url', t => { - viewJson(['pink@1.0.0', 'maintainers'], () => { + viewJson.exec(['pink@1.0.0', 'maintainers'], () => { t.matchSnapshot(logs) t.end() }) }) t.test('unknown nested field ', t => { - view(['yellow@1.0.0', 'dist.foobar'], () => { + view.exec(['yellow@1.0.0', 'dist.foobar'], () => { t.equals(logs, '', 'no info to display') t.end() }) }) t.test('array field - 1 element', t => { - view(['purple@1.0.0', 'maintainers.name'], () => { + view.exec(['purple@1.0.0', 'maintainers.name'], () => { t.matchSnapshot(logs) t.end() }) }) t.test('array field - 2 elements', t => { - view(['yellow@1.x.x', 'maintainers.name'], () => { + view.exec(['yellow@1.x.x', 'maintainers.name'], () => { t.matchSnapshot(logs) t.end() }) @@ -467,14 +467,13 @@ t.test('should log info by field name', t => { }) t.test('throw error if global mode', (t) => { - const view = requireInject('../../lib/view.js', { - '../../lib/npm.js': { - flatOptions: { - global: true, - }, + const View = requireInject('../../lib/view.js') + const view = new View({ + flatOptions: { + global: true, }, }) - view([], (err) => { + view.exec([], (err) => { t.equals(err.message, 'Cannot use view command in global mode.') t.end() }) @@ -483,15 +482,14 @@ t.test('throw error if global mode', (t) => { t.test('throw ENOENT error if package.json misisng', (t) => { const testDir = t.testdir({}) - const view = requireInject('../../lib/view.js', { - '../../lib/npm.js': { - prefix: testDir, - flatOptions: { - global: false, - }, + const View = requireInject('../../lib/view.js') + const view = new View({ + prefix: testDir, + flatOptions: { + global: false, }, }) - view([], (err) => { + view.exec([], (err) => { t.match(err, { code: 'ENOENT' }) t.end() }) @@ -502,15 +500,14 @@ t.test('throw EJSONPARSE error if package.json not json', (t) => { 'package.json': 'not json, nope, not even a little bit!', }) - const view = requireInject('../../lib/view.js', { - '../../lib/npm.js': { - prefix: testDir, - flatOptions: { - global: false, - }, + const View = requireInject('../../lib/view.js') + const view = new View({ + prefix: testDir, + flatOptions: { + global: false, }, }) - view([], (err) => { + view.exec([], (err) => { t.match(err, { code: 'EJSONPARSE' }) t.end() }) @@ -521,50 +518,49 @@ t.test('throw error if package.json has no name', (t) => { 'package.json': '{}', }) - const view = requireInject('../../lib/view.js', { - '../../lib/npm.js': { - prefix: testDir, - flatOptions: { - global: false, - }, + const View = requireInject('../../lib/view.js') + const view = new View({ + prefix: testDir, + flatOptions: { + global: false, }, }) - view([], (err) => { + view.exec([], (err) => { t.equals(err.message, 'Invalid package.json, no "name" field') t.end() }) }) t.test('throws when unpublished', (t) => { - const view = requireInject('../../lib/view.js', { - '../../lib/npm.js': { - flatOptions: { - defaultTag: '1.0.1', - global: false, - }, - }, + const View = requireInject('../../lib/view.js', { pacote: { packument, }, }) - view(['red'], (err) => { + const view = new View({ + flatOptions: { + defaultTag: '1.0.1', + global: false, + }, + }) + view.exec(['red'], (err) => { t.equals(err.code, 'E404') t.end() }) }) t.test('completion', async t => { - const view = requireInject('../../lib/view.js', { - '../../lib/npm.js': { - flatOptions: { - defaultTag: '1.0.1', - global: false, - }, - }, + const View = requireInject('../../lib/view.js', { pacote: { packument, }, }) + const view = new View({ + flatOptions: { + defaultTag: '1.0.1', + global: false, + }, + }) const res = await view.completion({ conf: { argv: { remain: ['npm', 'view', 'green@1.0.0'] } }, }) @@ -573,11 +569,10 @@ t.test('completion', async t => { }) t.test('no registry completion', async t => { - const view = requireInject('../../lib/view.js', { - '../../lib/npm.js': { - flatOptions: { - defaultTag: '1.0.1', - }, + const View = requireInject('../../lib/view.js') + const view = new View({ + flatOptions: { + defaultTag: '1.0.1', }, }) const res = await view.completion({conf: { argv: { remain: ['npm', 'view'] } } }) diff --git a/test/lib/whoami.js b/test/lib/whoami.js index d54814db3..3d9618ffa 100644 --- a/test/lib/whoami.js +++ b/test/lib/whoami.js @@ -3,15 +3,15 @@ const requireInject = require('require-inject') test('whoami', (t) => { t.plan(3) - const whoami = requireInject('../../lib/whoami.js', { + const Whoami = requireInject('../../lib/whoami.js', { '../../lib/utils/get-identity.js': () => Promise.resolve('foo'), - '../../lib/npm.js': { flatOptions: {} }, '../../lib/utils/output.js': (output) => { t.equal(output, 'foo', 'should output the username') }, }) + const whoami = new Whoami({ flatOptions: {} }) - whoami([], (err) => { + whoami.exec([], (err) => { t.ifError(err, 'npm whoami') t.ok('should successfully print username') }) @@ -19,15 +19,15 @@ test('whoami', (t) => { test('whoami json', (t) => { t.plan(3) - const whoami = requireInject('../../lib/whoami.js', { + const Whoami = requireInject('../../lib/whoami.js', { '../../lib/utils/get-identity.js': () => Promise.resolve('foo'), - '../../lib/npm.js': { flatOptions: { json: true } }, '../../lib/utils/output.js': (output) => { t.equal(output, '"foo"', 'should output the username as json') }, }) + const whoami = new Whoami({ flatOptions: { json: true } }) - whoami([], (err) => { + whoami.exec([], (err) => { t.ifError(err, 'npm whoami') t.ok('should successfully print username as json') }) |