const path = require('path'); const test = require('ava'); const sinon = require('sinon'); const mock = require('mock-fs'); const npm = require('../lib/plugin/npm/npm'); const { factory, runTasks } = require('./util'); const { getArgs } = require('./util/helpers'); test('should return npm package url', t => { const options = { npm: { name: 'my-cool-package' } }; const npmClient = factory(npm, { options }); t.is(npmClient.getPackageUrl(), 'https://www.npmjs.com/package/my-cool-package'); }); test('should return npm package url (custom registry)', t => { const options = { npm: { name: 'my-cool-package', publishConfig: { registry: 'https://my-registry.com/' } } }; const npmClient = factory(npm, { options }); t.is(npmClient.getPackageUrl(), 'https://my-registry.com/package/my-cool-package'); }); test('should return default tag', async t => { const npmClient = factory(npm); const tag = await npmClient.resolveTag(); t.is(tag, 'latest'); }); test('should resolve default tag for pre-release', async t => { const npmClient = factory(npm); const stub = sinon.stub(npmClient, 'getRegistryPreReleaseTags').resolves([]); const tag = await npmClient.resolveTag('1.0.0-0'); t.is(tag, 'next'); stub.restore(); }); test('should guess tag from registry for pre-release', async t => { const npmClient = factory(npm); const stub = sinon.stub(npmClient, 'getRegistryPreReleaseTags').resolves(['alpha']); const tag = await npmClient.resolveTag('1.0.0-0'); t.is(tag, 'alpha'); stub.restore(); }); test('should derive tag from pre-release version', async t => { const npmClient = factory(npm); const tag = await npmClient.resolveTag('1.0.2-alpha.3'); t.is(tag, 'alpha'); }); test('should use provided (default) tag even for pre-release', async t => { const options = { npm: { tag: 'latest' } }; const npmClient = factory(npm, { options }); const exec = sinon.stub(npmClient.shell, 'exec').resolves(); await npmClient.bump('1.0.0-next.0'); t.is(npmClient.getContext('tag'), 'latest'); exec.restore(); }); test('should warn when bumping to same version', async t => { const npmClient = factory(npm); const exec = sinon .stub(npmClient.shell, 'exec') .rejects('npm ERR! Version not changed, might want --allow-same-version'); await npmClient.bump('1.0.0-next.0'); t.is(npmClient.log.warn.firstCall.args[0], 'Did not update version in package.json, etc. (already at 1.0.0-next.0).'); exec.restore(); }); test('should return first pre-release tag from package in registry when resolving tag without pre-id', async t => { const npmClient = factory(npm); const response = { latest: '1.4.1', alpha: '2.0.0-alpha.1', beta: '2.0.0-beta.3' }; const exec = sinon.stub(npmClient.shell, 'exec').resolves(JSON.stringify(response)); t.is(await npmClient.resolveTag('2.0.0-5'), 'alpha'); exec.restore(); }); test('should return default pre-release tag when resolving tag without pre-id', async t => { const npmClient = factory(npm); const response = { latest: '1.4.1' }; const exec = sinon.stub(npmClient.shell, 'exec').resolves(JSON.stringify(response)); t.is(await npmClient.resolveTag('2.0.0-0'), 'next'); exec.restore(); }); test('should handle erroneous output when resolving tag without pre-id', async t => { const npmClient = factory(npm); const exec = sinon.stub(npmClient.shell, 'exec').resolves(''); t.is(await npmClient.resolveTag('2.0.0-0'), 'next'); exec.restore(); }); test('should handle errored request when resolving tag without pre-id', async t => { const npmClient = factory(npm); const exec = sinon.stub(npmClient.shell, 'exec').rejects(); t.is(await npmClient.resolveTag('2.0.0-0'), 'next'); exec.restore(); }); test('should add registry to commands when specified', async t => { const npmClient = factory(npm); npmClient.setContext({ publishConfig: { registry: 'registry.example.org' } }); const exec = sinon.stub(npmClient.shell, 'exec').resolves(); exec.withArgs('npm whoami --registry registry.example.org').resolves('john'); exec .withArgs('npm access ls-collaborators release-it --registry registry.example.org') .resolves(JSON.stringify({ john: ['write'] })); await runTasks(npmClient); t.is(exec.args[0][0], 'npm ping --registry registry.example.org'); t.is(exec.args[1][0], 'npm whoami --registry registry.example.org'); t.regex(exec.args[2][0], /npm show release-it@[a-z]+ version --registry registry\.example\.org/); exec.restore(); }); test('should not throw when executing tasks', async t => { const npmClient = factory(npm); const exec = sinon.stub(npmClient.shell, 'exec').resolves(); exec.withArgs('npm whoami').resolves('john'); exec.withArgs('npm access ls-collaborators release-it').resolves(JSON.stringify({ john: ['write'] })); await t.notThrowsAsync(runTasks(npmClient)); exec.restore(); }); test('should throw if npm is down', async t => { const npmClient = factory(npm); const exec = sinon.stub(npmClient.shell, 'exec').resolves(); exec.withArgs('npm ping').rejects(); await t.throwsAsync(runTasks(npmClient), { message: /^Unable to reach npm registry/ }); exec.restore(); }); test('should not throw if npm returns 400/404 for unsupported ping/whoami/access', async t => { const npmClient = factory(npm); const exec = sinon.stub(npmClient.shell, 'exec').resolves(); const pingError = "npm ERR! code E404\nnpm ERR! 404 Package '--ping' not found : ping"; const whoamiError = "npm ERR! code E404\nnpm ERR! 404 Package '--whoami' not found : whoami"; const accessError = 'npm ERR! code E400\nnpm ERR! 400 Bad Request - GET https://npm.example.org/-/collaborators'; exec.withArgs('npm ping').rejects(new Error(pingError)); exec.withArgs('npm whoami').rejects(new Error(whoamiError)); exec.withArgs('npm access').rejects(new Error(accessError)); await runTasks(npmClient); t.is(exec.lastCall.args[0].trim(), 'npm publish . --tag latest'); exec.restore(); }); test('should not throw if npm returns 400 for unsupported ping/whoami/access', async t => { const npmClient = factory(npm); const exec = sinon.stub(npmClient.shell, 'exec').resolves(); const pingError = 'npm ERR! code E400\nnpm ERR! 400 Bad Request - GET https://npm.example.org/-/ping?write=true'; const whoamiError = 'npm ERR! code E400\nnpm ERR! 400 Bad Request - GET https://npm.example.org/-/whoami'; const accessError = 'npm ERR! code E400\nnpm ERR! 400 Bad Request - GET https://npm.example.org/-/collaborators'; exec.withArgs('npm ping').rejects(new Error(pingError)); exec.withArgs('npm whoami').rejects(new Error(whoamiError)); exec.withArgs('npm access').rejects(new Error(accessError)); await runTasks(npmClient); t.is(exec.lastCall.args[0].trim(), 'npm publish . --tag latest'); exec.restore(); }); test('should not throw if npm returns 404 for unsupported ping', async t => { const npmClient = factory(npm); const exec = sinon.stub(npmClient.shell, 'exec').resolves(); const pingError = 'npm ERR!