| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455 |
- import fs from 'node:fs'
- import os from 'node:os'
- import path from 'node:path'
- import { describe, expect, it } from 'vitest'
- import { ClaudeLoginManager } from '../src/services/claude-login'
- // 模拟 `claude auth login` 的非交互行为:输出网址 → 读授权码 → 无效则提示并继续等待,有效则成功退出
- const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'fake-claude-'))
- const fake = path.join(dir, 'claude')
- fs.writeFileSync(fake, `#!/usr/bin/env node
- process.stdout.write('Opening browser to sign in…\\nIf the browser didn\\'t open, visit: https://claude.com/cai/oauth/authorize?code=true&state=abc\\nPaste code here if prompted > ')
- let buf = ''
- process.stdin.on('data', d => {
- buf += d
- const lines = buf.split('\\n'); buf = lines.pop()
- for (const l of lines) {
- if (l === 'good-code') { console.log('Login successful.'); process.exit(0) }
- else console.error('Invalid code. Please make sure the full code was copied.')
- }
- })
- `, { mode: 0o755 })
- describe('ClaudeLoginManager', () => {
- const audits: string[] = []
- const mgr = new ClaudeLoginManager(() => fake, s => audits.push(s))
- it('启动后返回登录网址;无效授权码可以重试;有效授权码完成登录', async () => {
- const start = await mgr.start({})
- expect(start.url).toBe('https://claude.com/cai/oauth/authorize?code=true&state=abc')
- await expect(mgr.start({})).rejects.toThrow(/已有一个登录流程/)
- const bad = await mgr.submitCode(start.id, 'wrong')
- expect(bad).toEqual({ ok: false, retry: true, message: expect.stringContaining('Invalid code') })
- const good = await mgr.submitCode(start.id, 'good-code')
- expect(good.ok).toBe(true)
- expect(mgr.current()).toBeNull()
- // 审计中不包含授权码
- expect(audits.join('\n')).not.toMatch(/good-code|wrong/)
- })
- it('取消后流程结束,旧 ID 不能再提交', async () => {
- const start = await mgr.start({ sso: true, email: 'a@b.com' })
- mgr.cancel(start.id)
- expect(mgr.current()).toBeNull()
- await expect(mgr.submitCode(start.id, 'good-code')).rejects.toThrow(/不存在/)
- })
- it('拒绝格式不正确的输入', async () => {
- await expect(mgr.start({ email: 'not-an-email' })).rejects.toThrow(/邮箱/)
- const start = await mgr.start({})
- await expect(mgr.submitCode(start.id, 'has space')).rejects.toThrow(/格式/)
- mgr.cancel(start.id)
- })
- })
|