From 06fd788f79e16da04d6e96aa56416cd2698f057a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20M=C3=B8ller=20Ellehauge?= Date: Wed, 22 Jun 2022 22:58:41 +0200 Subject: feat: prompt before opening web-login URL when performing `login`/`adduser` (#4960) Prompt before opening web-login URL when performing login/adduser --- test/lib/auth/legacy.js | 2 +- test/lib/utils/open-url-prompt.js | 150 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 test/lib/utils/open-url-prompt.js (limited to 'test') diff --git a/test/lib/auth/legacy.js b/test/lib/auth/legacy.js index 0c23f8ba6..39d977d43 100644 --- a/test/lib/auth/legacy.js +++ b/test/lib/auth/legacy.js @@ -12,7 +12,7 @@ const legacy = t.mock('../../../lib/auth/legacy.js', { }, }, 'npm-profile': profile, - '../../../lib/utils/open-url.js': (npm, url, msg) => { + '../../../lib/utils/open-url-prompt.js': (_npm, url) => { if (!url) { throw Object.assign(new Error('failed open url'), { code: 'ERROR' }) } diff --git a/test/lib/utils/open-url-prompt.js b/test/lib/utils/open-url-prompt.js new file mode 100644 index 000000000..6908e36b7 --- /dev/null +++ b/test/lib/utils/open-url-prompt.js @@ -0,0 +1,150 @@ +const t = require('tap') +const mockGlobals = require('../../fixtures/mock-globals.js') +const EventEmitter = require('events') + +const OUTPUT = [] +const output = (...args) => OUTPUT.push(args) +const npm = { + _config: { + json: false, + browser: true, + }, + config: { + get: k => npm._config[k], + set: (k, v) => { + npm._config[k] = v + }, + }, + output, +} + +let openerUrl = null +let openerOpts = null +let openerResult = null +const opener = (url, opts, cb) => { + openerUrl = url + openerOpts = opts + return cb(openerResult) +} + +let questionShouldResolve = true +const readline = { + createInterface: () => ({ + question: (_q, cb) => { + if (questionShouldResolve === true) { + cb() + } + }, + close: () => {}, + }), +} + +const openUrlPrompt = t.mock('../../../lib/utils/open-url-prompt.js', { + opener, + readline, +}) + +mockGlobals(t, { + 'process.stdin.isTTY': true, + 'process.stdout.isTTY': true, +}) + +t.test('does not open a url in non-interactive environments', async t => { + t.teardown(() => { + openerUrl = null + openerOpts = null + OUTPUT.length = 0 + }) + + mockGlobals(t, { + 'process.stdin.isTTY': false, + 'process.stdout.isTTY': false, + }) + + await openUrlPrompt(npm, 'https://www.npmjs.com', 'npm home', 'prompt') + t.equal(openerUrl, null, 'did not open') + t.same(openerOpts, null, 'did not open') +}) + +t.test('opens a url', async t => { + t.teardown(() => { + openerUrl = null + openerOpts = null + OUTPUT.length = 0 + npm._config.browser = true + }) + + npm._config.browser = 'browser' + await openUrlPrompt(npm, 'https://www.npmjs.com', 'npm home', 'prompt') + t.equal(openerUrl, 'https://www.npmjs.com', 'opened the given url') + t.same(openerOpts, { command: 'browser' }, 'passed command as null (the default)') + t.matchSnapshot(OUTPUT) +}) + +t.test('prints json output', async t => { + t.teardown(() => { + openerUrl = null + openerOpts = null + OUTPUT.length = 0 + npm._config.json = false + }) + + npm._config.json = true + await openUrlPrompt(npm, 'https://www.npmjs.com', 'npm home', 'prompt') + t.matchSnapshot(OUTPUT) +}) + +t.test('returns error for non-https url', async t => { + t.teardown(() => { + openerUrl = null + openerOpts = null + OUTPUT.length = 0 + }) + await t.rejects( + openUrlPrompt(npm, 'ftp://www.npmjs.com', 'npm home', 'prompt'), + /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.test('does not open url if canceled', async t => { + t.teardown(() => { + openerUrl = null + openerOpts = null + OUTPUT.length = 0 + questionShouldResolve = true + }) + + questionShouldResolve = false + const emitter = new EventEmitter() + + const open = openUrlPrompt(npm, 'https://www.npmjs.com', 'npm home', 'prompt', emitter) + + emitter.emit('abort') + + await open + + t.equal(openerUrl, null, 'did not open') + t.same(openerOpts, null, 'did not open') +}) + +t.test('returns error when opener errors', async t => { + t.teardown(() => { + openerUrl = null + openerOpts = null + openerResult = null + OUTPUT.length = 0 + }) + + openerResult = new Error('Opener failed') + + await t.rejects( + openUrlPrompt(npm, 'https://www.npmjs.com', 'npm home', 'prompt'), + /Opener failed/, + 'got the correct error' + ) + t.equal(openerUrl, 'https://www.npmjs.com', 'did not open') +}) -- cgit v1.2.3