Sifa professional network API (Fastify, AT Protocol, Jetstream) sifa.id/
at main 108 lines 3.8 kB view raw
1import { describe, expect, it } from 'vitest'; 2import { normalizeUrl, extractPlatformUsername } from '../../src/lib/url-utils.js'; 3 4describe('url-utils', () => { 5 describe('normalizeUrl', () => { 6 it('strips https protocol', () => { 7 expect(normalizeUrl('https://github.com/gxjansen')).toBe('github.com/gxjansen'); 8 }); 9 10 it('strips http protocol', () => { 11 expect(normalizeUrl('http://github.com/gxjansen')).toBe('github.com/gxjansen'); 12 }); 13 14 it('strips trailing slash', () => { 15 expect(normalizeUrl('https://github.com/gxjansen/')).toBe('github.com/gxjansen'); 16 }); 17 18 it('strips www prefix', () => { 19 expect(normalizeUrl('https://www.linkedin.com/in/gxjansen')).toBe('linkedin.com/in/gxjansen'); 20 }); 21 22 it('lowercases the URL', () => { 23 expect(normalizeUrl('https://GitHub.COM/GxJansen')).toBe('github.com/gxjansen'); 24 }); 25 26 it('handles multiple normalizations together', () => { 27 expect(normalizeUrl('HTTP://WWW.GitHub.Com/GxJansen/')).toBe('github.com/gxjansen'); 28 }); 29 30 it('handles URLs without protocol', () => { 31 expect(normalizeUrl('github.com/gxjansen')).toBe('github.com/gxjansen'); 32 }); 33 34 it('handles empty string', () => { 35 expect(normalizeUrl('')).toBe(''); 36 }); 37 38 it('strips multiple trailing slashes', () => { 39 expect(normalizeUrl('https://example.com///')).toBe('example.com'); 40 }); 41 }); 42 43 describe('extractPlatformUsername', () => { 44 it('extracts GitHub username', () => { 45 expect(extractPlatformUsername('github', 'https://github.com/gxjansen')).toBe('gxjansen'); 46 }); 47 48 it('extracts GitHub username with trailing slash', () => { 49 expect(extractPlatformUsername('github', 'https://github.com/gxjansen/')).toBe('gxjansen'); 50 }); 51 52 it('extracts LinkedIn username', () => { 53 expect(extractPlatformUsername('linkedin', 'https://www.linkedin.com/in/gxjansen')).toBe( 54 'gxjansen', 55 ); 56 }); 57 58 it('extracts LinkedIn username with trailing slash', () => { 59 expect(extractPlatformUsername('linkedin', 'https://linkedin.com/in/gxjansen/')).toBe( 60 'gxjansen', 61 ); 62 }); 63 64 it('extracts Twitter/X username from twitter.com', () => { 65 expect(extractPlatformUsername('twitter', 'https://twitter.com/guido')).toBe('guido'); 66 }); 67 68 it('extracts Twitter/X username from x.com', () => { 69 expect(extractPlatformUsername('twitter', 'https://x.com/guido')).toBe('guido'); 70 }); 71 72 it('extracts Instagram username', () => { 73 expect(extractPlatformUsername('instagram', 'https://instagram.com/guido')).toBe('guido'); 74 }); 75 76 it('extracts YouTube channel ID', () => { 77 expect(extractPlatformUsername('youtube', 'https://youtube.com/channel/UC1234abc')).toBe( 78 'UC1234abc', 79 ); 80 }); 81 82 it('extracts YouTube custom handle', () => { 83 expect(extractPlatformUsername('youtube', 'https://youtube.com/@guido')).toBe('@guido'); 84 }); 85 86 it('extracts Fediverse username from URL', () => { 87 expect(extractPlatformUsername('fediverse', 'https://mastodon.social/@guido')).toBe( 88 '@guido@mastodon.social', 89 ); 90 }); 91 92 it('returns null for unknown platform', () => { 93 expect(extractPlatformUsername('other', 'https://example.com/user')).toBeNull(); 94 }); 95 96 it('returns null for malformed URL', () => { 97 expect(extractPlatformUsername('github', 'not-a-url')).toBeNull(); 98 }); 99 100 it('returns null for GitHub URL without username path', () => { 101 expect(extractPlatformUsername('github', 'https://github.com')).toBeNull(); 102 }); 103 104 it('is case-insensitive for platform matching', () => { 105 expect(extractPlatformUsername('GitHub', 'https://github.com/gxjansen')).toBe('gxjansen'); 106 }); 107 }); 108});