11cb0ef41Sopenharmony_ciconst t = require('tap')
21cb0ef41Sopenharmony_ciconst EventEmitter = require('events')
31cb0ef41Sopenharmony_ciconst tmock = require('../../fixtures/tmock')
41cb0ef41Sopenharmony_ciconst mockNpm = require('../../fixtures/mock-npm')
51cb0ef41Sopenharmony_ci
61cb0ef41Sopenharmony_ciconst mockOpenUrlPrompt = async (t, {
71cb0ef41Sopenharmony_ci  questionShouldResolve = true,
81cb0ef41Sopenharmony_ci  openUrlPromptInterrupted = false,
91cb0ef41Sopenharmony_ci  openerResult = null,
101cb0ef41Sopenharmony_ci  isTTY = true,
111cb0ef41Sopenharmony_ci  emitter = null,
121cb0ef41Sopenharmony_ci  url: openUrl = 'https://www.npmjs.com',
131cb0ef41Sopenharmony_ci  ...config
141cb0ef41Sopenharmony_ci}) => {
151cb0ef41Sopenharmony_ci  const mock = await mockNpm(t, {
161cb0ef41Sopenharmony_ci    globals: {
171cb0ef41Sopenharmony_ci      'process.stdin.isTTY': isTTY,
181cb0ef41Sopenharmony_ci      'process.stdout.isTTY': isTTY,
191cb0ef41Sopenharmony_ci    },
201cb0ef41Sopenharmony_ci    config,
211cb0ef41Sopenharmony_ci  })
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_ci  let openerUrl = null
241cb0ef41Sopenharmony_ci  let openerOpts = null
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_ci  const openUrlPrompt = tmock(t, '{LIB}/utils/open-url-prompt.js', {
271cb0ef41Sopenharmony_ci    '@npmcli/promise-spawn': {
281cb0ef41Sopenharmony_ci      open: async (url, options) => {
291cb0ef41Sopenharmony_ci        openerUrl = url
301cb0ef41Sopenharmony_ci        openerOpts = options
311cb0ef41Sopenharmony_ci        if (openerResult) {
321cb0ef41Sopenharmony_ci          throw openerResult
331cb0ef41Sopenharmony_ci        }
341cb0ef41Sopenharmony_ci      },
351cb0ef41Sopenharmony_ci    },
361cb0ef41Sopenharmony_ci    readline: {
371cb0ef41Sopenharmony_ci      createInterface: () => ({
381cb0ef41Sopenharmony_ci        question: (_q, cb) => {
391cb0ef41Sopenharmony_ci          if (questionShouldResolve === true) {
401cb0ef41Sopenharmony_ci            cb()
411cb0ef41Sopenharmony_ci          }
421cb0ef41Sopenharmony_ci        },
431cb0ef41Sopenharmony_ci        close: () => {},
441cb0ef41Sopenharmony_ci        on: (_signal, cb) => {
451cb0ef41Sopenharmony_ci          if (openUrlPromptInterrupted && _signal === 'SIGINT') {
461cb0ef41Sopenharmony_ci            cb()
471cb0ef41Sopenharmony_ci          }
481cb0ef41Sopenharmony_ci        },
491cb0ef41Sopenharmony_ci      }),
501cb0ef41Sopenharmony_ci    },
511cb0ef41Sopenharmony_ci  })
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_ci  let error
541cb0ef41Sopenharmony_ci  const args = [mock.npm, openUrl, 'npm home', 'prompt']
551cb0ef41Sopenharmony_ci  if (emitter) {
561cb0ef41Sopenharmony_ci    mock.open = openUrlPrompt(...args, emitter)
571cb0ef41Sopenharmony_ci  } else {
581cb0ef41Sopenharmony_ci    await openUrlPrompt(...args).catch((er) => error = er)
591cb0ef41Sopenharmony_ci  }
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci  return {
621cb0ef41Sopenharmony_ci    ...mock,
631cb0ef41Sopenharmony_ci    openerUrl,
641cb0ef41Sopenharmony_ci    openerOpts,
651cb0ef41Sopenharmony_ci    OUTPUT: mock.joinedOutput(),
661cb0ef41Sopenharmony_ci    emitter,
671cb0ef41Sopenharmony_ci    error,
681cb0ef41Sopenharmony_ci  }
691cb0ef41Sopenharmony_ci}
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_cit.test('does not open a url in non-interactive environments', async t => {
721cb0ef41Sopenharmony_ci  const { openerUrl, openerOpts } = await mockOpenUrlPrompt(t, { isTTY: false })
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ci  t.equal(openerUrl, null, 'did not open')
751cb0ef41Sopenharmony_ci  t.same(openerOpts, null, 'did not open')
761cb0ef41Sopenharmony_ci})
771cb0ef41Sopenharmony_ci
781cb0ef41Sopenharmony_cit.test('opens a url', async t => {
791cb0ef41Sopenharmony_ci  const { OUTPUT, openerUrl, openerOpts } = await mockOpenUrlPrompt(t, { browser: true })
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci  t.equal(openerUrl, 'https://www.npmjs.com', 'opened the given url')
821cb0ef41Sopenharmony_ci  t.same(openerOpts, { command: null }, 'passed command as null (the default)')
831cb0ef41Sopenharmony_ci  t.matchSnapshot(OUTPUT)
841cb0ef41Sopenharmony_ci})
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_cit.test('opens a url with browser string', async t => {
871cb0ef41Sopenharmony_ci  const { openerUrl, openerOpts } = await mockOpenUrlPrompt(t, { browser: 'firefox' })
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ci  t.equal(openerUrl, 'https://www.npmjs.com', 'opened the given url')
901cb0ef41Sopenharmony_ci  // FIXME: browser string is parsed as a boolean in config layer
911cb0ef41Sopenharmony_ci  // this is a bug that should be fixed or the config should not allow it
921cb0ef41Sopenharmony_ci  t.same(openerOpts, { command: null }, 'passed command as null (the default)')
931cb0ef41Sopenharmony_ci})
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_cit.test('prints json output', async t => {
961cb0ef41Sopenharmony_ci  const { OUTPUT } = await mockOpenUrlPrompt(t, { json: true })
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_ci  t.matchSnapshot(OUTPUT)
991cb0ef41Sopenharmony_ci})
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_cit.test('returns error for non-https url', async t => {
1021cb0ef41Sopenharmony_ci  const { error, OUTPUT, openerUrl, openerOpts } = await mockOpenUrlPrompt(t, {
1031cb0ef41Sopenharmony_ci    url: 'ftp://www.npmjs.com',
1041cb0ef41Sopenharmony_ci  })
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ci  t.match(error, /Invalid URL/, 'got the correct error')
1071cb0ef41Sopenharmony_ci  t.equal(openerUrl, null, 'did not open')
1081cb0ef41Sopenharmony_ci  t.same(openerOpts, null, 'did not open')
1091cb0ef41Sopenharmony_ci  t.same(OUTPUT, '', 'printed no output')
1101cb0ef41Sopenharmony_ci})
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_cit.test('does not open url if canceled', async t => {
1131cb0ef41Sopenharmony_ci  const emitter = new EventEmitter()
1141cb0ef41Sopenharmony_ci  const { openerUrl, openerOpts, open } = await mockOpenUrlPrompt(t, {
1151cb0ef41Sopenharmony_ci    questionShouldResolve: false,
1161cb0ef41Sopenharmony_ci    emitter,
1171cb0ef41Sopenharmony_ci  })
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_ci  emitter.emit('abort')
1201cb0ef41Sopenharmony_ci
1211cb0ef41Sopenharmony_ci  await open
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci  t.equal(openerUrl, null, 'did not open')
1241cb0ef41Sopenharmony_ci  t.same(openerOpts, null, 'did not open')
1251cb0ef41Sopenharmony_ci})
1261cb0ef41Sopenharmony_ci
1271cb0ef41Sopenharmony_cit.test('returns error when opener errors', async t => {
1281cb0ef41Sopenharmony_ci  const { error, openerUrl } = await mockOpenUrlPrompt(t, {
1291cb0ef41Sopenharmony_ci    openerResult: Object.assign(new Error('Opener failed'), { code: 1 }),
1301cb0ef41Sopenharmony_ci  })
1311cb0ef41Sopenharmony_ci
1321cb0ef41Sopenharmony_ci  t.match(error, /Opener failed/, 'got the correct error')
1331cb0ef41Sopenharmony_ci  t.equal(openerUrl, 'https://www.npmjs.com', 'did not open')
1341cb0ef41Sopenharmony_ci})
1351cb0ef41Sopenharmony_ci
1361cb0ef41Sopenharmony_cit.test('does not error when opener can not find command', async t => {
1371cb0ef41Sopenharmony_ci  const { OUTPUT, error, openerUrl } = await mockOpenUrlPrompt(t, {
1381cb0ef41Sopenharmony_ci    // openerResult: new Error('Opener failed'),
1391cb0ef41Sopenharmony_ci    openerResult: Object.assign(new Error('Opener failed'), { code: 127 }),
1401cb0ef41Sopenharmony_ci  })
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_ci  t.notOk(error, 'Did not error')
1431cb0ef41Sopenharmony_ci  t.equal(openerUrl, 'https://www.npmjs.com', 'did not open')
1441cb0ef41Sopenharmony_ci  t.matchSnapshot(OUTPUT, 'Outputs extra Browser unavailable message and url')
1451cb0ef41Sopenharmony_ci})
1461cb0ef41Sopenharmony_ci
1471cb0ef41Sopenharmony_cit.test('throws "canceled" error on SIGINT', async t => {
1481cb0ef41Sopenharmony_ci  const emitter = new EventEmitter()
1491cb0ef41Sopenharmony_ci  const { open } = await mockOpenUrlPrompt(t, {
1501cb0ef41Sopenharmony_ci    questionShouldResolve: false,
1511cb0ef41Sopenharmony_ci    openUrlPromptInterrupted: true,
1521cb0ef41Sopenharmony_ci    emitter,
1531cb0ef41Sopenharmony_ci  })
1541cb0ef41Sopenharmony_ci
1551cb0ef41Sopenharmony_ci  await t.rejects(open, /canceled/, 'message is canceled')
1561cb0ef41Sopenharmony_ci})
157