import { describe, expect, it } from 'vitest'; import { loginErrorKind, normalizeHandleInput } from './handle-input'; const ok = (value: string) => ({ ok: true, value }); describe('normalizeHandleInput', () => { it('passes a plain handle through, lowercased', () => { expect(normalizeHandleInput('Erlend.sh')).toEqual(ok('erlend.sh')); }); it('strips a leading @ and surrounding or invisible whitespace', () => { expect(normalizeHandleInput(' @name.bsky.social ')).toEqual(ok('name.bsky.social')); expect(normalizeHandleInput('\u200bname.bsky.social\u00a0')).toEqual(ok('name.bsky.social')); }); it('completes a bare name to bsky.social', () => { expect(normalizeHandleInput('Name')).toEqual(ok('name.bsky.social')); expect(normalizeHandleInput('@name')).toEqual(ok('name.bsky.social')); }); it('drops a trailing dot', () => { expect(normalizeHandleInput('name.bsky.social.')).toEqual(ok('name.bsky.social')); }); it('extracts the handle or DID from a pasted bsky.app profile URL', () => { expect(normalizeHandleInput('https://bsky.app/profile/Name.bsky.social/post/abc')).toEqual( ok('name.bsky.social'), ); expect(normalizeHandleInput('https://bsky.app/profile/did:plc:abc123')).toEqual(ok('did:plc:abc123')); }); it('passes other URLs (PDS sign-in) and DIDs through untouched', () => { expect(normalizeHandleInput('https://eurosky.social')).toEqual(ok('https://eurosky.social')); expect(normalizeHandleInput('did:web:Example.com')).toEqual(ok('did:web:Example.com')); expect(normalizeHandleInput('at://did:plc:abc123')).toEqual(ok('did:plc:abc123')); }); it('rejects an email address and empty input', () => { expect(normalizeHandleInput('me@example.com')).toEqual({ ok: false, reason: 'email' }); expect(normalizeHandleInput(' ')).toEqual({ ok: false, reason: 'empty' }); expect(normalizeHandleInput('@')).toEqual({ ok: false, reason: 'empty' }); }); }); describe('loginErrorKind', () => { it('classifies identity-resolution failures as handle errors', () => { expect(loginErrorKind(new Error('Invalid handle "x" provided.'))).toBe('handle'); expect(loginErrorKind(new Error('Handle "x.bsky.social" does not resolve to a DID'))).toBe('handle'); expect(loginErrorKind(new Error('Did document for "did:plc:x" does not include the handle "y"'))).toBe( 'handle', ); }); it('classifies everything else as generic', () => { expect(loginErrorKind(new Error('Failed to fetch'))).toBe('generic'); expect(loginErrorKind('boom')).toBe('generic'); }); });