• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1const t = require('tap')
2const fs = require('fs')
3const path = require('path')
4const ini = require('ini')
5
6const { load: loadMockNpm } = require('../../fixtures/mock-npm.js')
7const mockGlobals = require('@npmcli/mock-globals')
8const MockRegistry = require('@npmcli/mock-registry')
9const stream = require('stream')
10
11const mockLogin = async (t, { stdin: stdinLines, registry: registryUrl, ...options } = {}) => {
12  let stdin
13  if (stdinLines) {
14    stdin = new stream.PassThrough()
15    for (const l of stdinLines) {
16      stdin.write(l + '\n')
17    }
18    mockGlobals(t, {
19      'process.stdin': stdin,
20      'process.stdout': new stream.PassThrough(), // to quiet readline
21    }, { replace: true })
22  }
23  const mock = await loadMockNpm(t, {
24    ...options,
25    command: 'login',
26  })
27  const registry = new MockRegistry({
28    tap: t,
29    registry: registryUrl ?? mock.npm.config.get('registry'),
30  })
31  return {
32    registry,
33    stdin,
34    rc: () => ini.parse(fs.readFileSync(path.join(mock.home, '.npmrc'), 'utf8')),
35    ...mock,
36  }
37}
38
39t.test('usage', async t => {
40  const { login } = await loadMockNpm(t, { command: 'login' })
41  t.match(login.usage, 'login', 'usage has command name in it')
42})
43
44t.test('legacy', t => {
45  t.test('basic login', async t => {
46    const { npm, registry, login, rc } = await mockLogin(t, {
47      stdin: ['test-user', 'test-password'],
48      config: { 'auth-type': 'legacy' },
49      homeDir: {
50        '.npmrc': [
51          '//registry.npmjs.org/:_authToken=user',
52          '//registry.npmjs.org/:always-auth=user',
53          '//registry.npmjs.org/:email=test-email-old@npmjs.org',
54        ].join('\n'),
55      },
56    })
57    registry.couchlogin({
58      username: 'test-user',
59      password: 'test-password',
60      token: 'npm_test-token',
61    })
62    await login.exec([])
63    t.same(npm.config.get('//registry.npmjs.org/:_authToken'), 'npm_test-token')
64    t.same(rc(), {
65      '//registry.npmjs.org/:_authToken': 'npm_test-token',
66      email: 'test-email-old@npmjs.org',
67    }, 'should only have token and un-nerfed old email')
68  })
69
70  t.test('scoped login default registry', async t => {
71    const { npm, registry, login, rc } = await mockLogin(t, {
72      stdin: ['test-user', 'test-password'],
73      config: {
74        'auth-type': 'legacy',
75        scope: '@npmcli',
76      },
77    })
78    registry.couchlogin({
79      username: 'test-user',
80      password: 'test-password',
81      token: 'npm_test-token',
82    })
83    await login.exec([])
84    t.same(npm.config.get('//registry.npmjs.org/:_authToken'), 'npm_test-token')
85    t.same(npm.config.get('@npmcli:registry'), 'https://registry.npmjs.org/')
86    t.same(rc(), {
87      '//registry.npmjs.org/:_authToken': 'npm_test-token',
88      '@npmcli:registry': 'https://registry.npmjs.org/',
89    }, 'should only have token and scope:registry')
90  })
91
92  t.test('scoped login scoped registry', async t => {
93    const { npm, registry, login, rc } = await mockLogin(t, {
94      stdin: ['test-user', 'test-password'],
95      registry: 'https://diff-registry.npmjs.org',
96      config: {
97        'auth-type': 'legacy',
98        scope: '@npmcli',
99      },
100      homeDir: {
101        '.npmrc': '@npmcli:registry=https://diff-registry.npmjs.org',
102      },
103    })
104    registry.couchlogin({
105      username: 'test-user',
106      password: 'test-password',
107      token: 'npm_test-token',
108    })
109    await login.exec([])
110    t.same(npm.config.get('//diff-registry.npmjs.org/:_authToken'), 'npm_test-token')
111    t.same(npm.config.get('@npmcli:registry'), 'https://diff-registry.npmjs.org')
112    t.same(rc(), {
113      '@npmcli:registry': 'https://diff-registry.npmjs.org',
114      '//diff-registry.npmjs.org/:_authToken': 'npm_test-token',
115    }, 'should only have token and scope:registry')
116  })
117  t.end()
118})
119
120t.test('web', t => {
121  t.test('basic login', async t => {
122    const { npm, registry, login, rc } = await mockLogin(t, {
123      config: { 'auth-type': 'web' },
124    })
125    registry.weblogin({ token: 'npm_test-token' })
126    await login.exec([])
127    t.same(npm.config.get('//registry.npmjs.org/:_authToken'), 'npm_test-token')
128    t.same(rc(), {
129      '//registry.npmjs.org/:_authToken': 'npm_test-token',
130    })
131  })
132  t.test('server error', async t => {
133    const { registry, login } = await mockLogin(t, {
134      config: { 'auth-type': 'web' },
135    })
136    registry.nock.post(registry.fullPath('/-/v1/login'))
137      .reply(503, {})
138    await t.rejects(
139      login.exec([]),
140      { message: /503/ }
141    )
142  })
143  t.test('fallback', async t => {
144    const { npm, registry, login } = await mockLogin(t, {
145      stdin: ['test-user', 'test-password'],
146      config: { 'auth-type': 'web' },
147    })
148    registry.nock.post(registry.fullPath('/-/v1/login'))
149      .reply(404, {})
150    registry.couchlogin({
151      username: 'test-user',
152      password: 'test-password',
153      token: 'npm_test-token',
154    })
155    await login.exec([])
156    t.same(npm.config.get('//registry.npmjs.org/:_authToken'), 'npm_test-token')
157  })
158  t.end()
159})
160