• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1const t = require('tap')
2const setupMockNpm = require('../../fixtures/mock-npm')
3const tmock = require('../../fixtures/tmock')
4
5const setupOtplease = async (t, { otp = {}, ...rest }, fn) => {
6  const readUserInfo = {
7    otp: async () => '1234',
8  }
9
10  const webAuth = async (opener) => {
11    opener()
12    return '1234'
13  }
14
15  const otplease = tmock(t, '{LIB}/utils/otplease.js', {
16    '{LIB}/utils/read-user-info.js': readUserInfo,
17    '{LIB}/utils/open-url-prompt.js': () => {},
18    '{LIB}/utils/web-auth': webAuth,
19  })
20
21  const { npm } = await setupMockNpm(t, rest)
22
23  return await otplease(npm, otp, fn)
24}
25
26t.test('returns function results on success', async (t) => {
27  const result = await setupOtplease(t, {}, () => 'test string')
28  t.equal('test string', result)
29})
30
31t.test('returns function results on otp success', async (t) => {
32  const fn = ({ otp }) => {
33    if (otp) {
34      return 'success'
35    }
36    throw Object.assign(new Error('nope'), { code: 'EOTP' })
37  }
38
39  const result = await setupOtplease(t, {
40    globals: {
41      'process.stdin': { isTTY: true },
42      'process.stdout': { isTTY: true },
43    },
44  }, fn)
45
46  t.equal('success', result)
47})
48
49t.test('prompts for otp for EOTP', async (t) => {
50  let called = false
51
52  const fn = async (opts) => {
53    if (!called) {
54      called = true
55      throw Object.assign(new Error('nope'), { code: 'EOTP' })
56    }
57    return opts
58  }
59
60  const result = await setupOtplease(t, {
61    otp: { some: 'prop' },
62    globals: {
63      'process.stdin': { isTTY: true },
64      'process.stdout': { isTTY: true },
65    },
66  }, fn)
67
68  t.strictSame(result, { some: 'prop', otp: '1234' })
69})
70
71t.test('returns function results on webauth success', async (t) => {
72  const fn = ({ otp }) => {
73    if (otp) {
74      return 'success'
75    }
76    throw Object.assign(new Error('nope'), {
77      code: 'EOTP',
78      body: {
79        authUrl: 'https://www.example.com/auth',
80        doneUrl: 'https://www.example.com/done',
81      },
82    })
83  }
84
85  const result = await setupOtplease(t, {
86    config: { browser: 'firefox' },
87    globals: {
88      'process.stdin': { isTTY: true },
89      'process.stdout': { isTTY: true },
90    },
91  }, fn)
92
93  t.equal('success', result)
94})
95
96t.test('prompts for otp for 401', async (t) => {
97  let called = false
98
99  const fn = async (opts) => {
100    if (!called) {
101      called = true
102      throw Object.assign(new Error('nope'), {
103        code: 'E401',
104        body: 'one-time pass required',
105      })
106    }
107
108    return opts
109  }
110
111  const result = await setupOtplease(t, {
112    globals: {
113      'process.stdin': { isTTY: true },
114      'process.stdout': { isTTY: true },
115    },
116  }, fn)
117
118  t.strictSame(result, { otp: '1234' })
119})
120
121t.test('does not prompt for non-otp errors', async (t) => {
122  const fn = async (opts) => {
123    throw new Error('nope')
124  }
125
126  await t.rejects(setupOtplease(t, {
127    globals: {
128      'process.stdin': { isTTY: true },
129      'process.stdout': { isTTY: true },
130    },
131  }, fn), { message: 'nope' }, 'rejects with the original error')
132})
133
134t.test('does not prompt if stdin or stdout is not a tty', async (t) => {
135  const fn = async (opts) => {
136    throw Object.assign(new Error('nope'), { code: 'EOTP' })
137  }
138
139  await t.rejects(setupOtplease(t, {
140    globals: {
141      'process.stdin': { isTTY: false },
142      'process.stdout': { isTTY: false },
143    },
144  }, fn), { message: 'nope' }, 'rejects with the original error')
145})
146