Notarize AT Protocol records on Ethereum using EAS (experiment)
at main 3.7 kB view raw
1import { describe, it, expect } from 'vitest'; 2import { parseRecordURI, hashContent, getExplorerURL } from '../../src/lib/utils'; 3 4describe('parseRecordURI', () => { 5 it('should parse valid AT Protocol URI', () => { 6 const uri = 'at://did:plc:abc123/app.bsky.feed.post/xyz789'; 7 const result = parseRecordURI(uri); 8 9 expect(result.did).toBe('did:plc:abc123'); 10 expect(result.collection).toBe('app.bsky.feed.post'); 11 expect(result.rkey).toBe('xyz789'); 12 }); 13 14 it('should handle complex DIDs', () => { 15 const uri = 'at://did:plc:z72i7hdynmk6r22z27h6tvur/com.whtwnd.blog.entry/abc123'; 16 const result = parseRecordURI(uri); 17 18 expect(result.did).toBe('did:plc:z72i7hdynmk6r22z27h6tvur'); 19 expect(result.collection).toBe('com.whtwnd.blog.entry'); 20 expect(result.rkey).toBe('abc123'); 21 }); 22 23 it('should throw on invalid URI format', () => { 24 expect(() => parseRecordURI('invalid-uri')).toThrow('Invalid AT Protocol URI format'); 25 expect(() => parseRecordURI('https://example.com')).toThrow('Invalid AT Protocol URI format'); 26 expect(() => parseRecordURI('at://invalid')).toThrow('Invalid AT Protocol URI format'); 27 }); 28}); 29 30describe('hashContent', () => { 31 it('should generate consistent SHA-256 hash', () => { 32 const content = { text: 'Hello World', createdAt: '2024-01-01' }; 33 const hash1 = hashContent(content); 34 const hash2 = hashContent(content); 35 36 expect(hash1).toBe(hash2); 37 expect(hash1).toMatch(/^0x[a-f0-9]{64}$/); 38 }); 39 40 it('should generate different hashes for different content', () => { 41 const content1 = { text: 'Hello' }; 42 const content2 = { text: 'World' }; 43 44 expect(hashContent(content1)).not.toBe(hashContent(content2)); 45 }); 46 47 it('should be order-sensitive', () => { 48 const content1 = { a: 1, b: 2 }; 49 const content2 = { b: 2, a: 1 }; 50 51 // JSON.stringify is order-sensitive 52 const hash1 = hashContent(content1); 53 const hash2 = hashContent(content2); 54 55 expect(hash1).toBeTruthy(); 56 expect(hash2).toBeTruthy(); 57 }); 58}); 59 60describe('getExplorerURL', () => { 61 it('should generate correct explorer URL for sepolia', () => { 62 const uid = '0xabc123'; 63 const url = getExplorerURL(uid, 'sepolia'); 64 65 expect(url).toBe('https://sepolia.easscan.org/attestation/view/0xabc123'); 66 }); 67 68 it('should generate correct explorer URL for sepolia', () => { 69 const uid = '0xabc123'; 70 const url = getExplorerURL(uid, 'sepolia'); 71 72 expect(url).toBe('https://sepolia.easscan.org/attestation/view/0xabc123'); 73 }); 74 75 it('should default to sepolia for unknown network', () => { 76 const uid = '0xabc123'; 77 const url = getExplorerURL(uid, 'unknown-network'); 78 79 expect(url).toBe('https://sepolia.easscan.org/attestation/view/0xabc123'); 80 }); 81}); 82 83describe('hashContent', () => { 84 it('should generate consistent SHA-256 hash', () => { 85 const content = { text: 'Hello World', createdAt: '2024-01-01' }; 86 const hash1 = hashContent(content); 87 const hash2 = hashContent(content); 88 89 expect(hash1).toBe(hash2); 90 expect(hash1).toMatch(/^0x[a-f0-9]{64}$/); 91 }); 92 93 it('should be order-independent', () => { 94 const content1 = { a: 1, b: 2, c: 3 }; 95 const content2 = { c: 3, a: 1, b: 2 }; 96 const content3 = { b: 2, c: 3, a: 1 }; 97 98 const hash1 = hashContent(content1); 99 const hash2 = hashContent(content2); 100 const hash3 = hashContent(content3); 101 102 expect(hash1).toBe(hash2); 103 expect(hash2).toBe(hash3); 104 }); 105 106 it('should handle nested objects', () => { 107 const content1 = { outer: { b: 2, a: 1 }, x: 5 }; 108 const content2 = { x: 5, outer: { a: 1, b: 2 } }; 109 110 expect(hashContent(content1)).toBe(hashContent(content2)); 111 }); 112});