A calm place to write long-form, and publish it to the open social web. skypress.blog/
0

Configure Feed

Select the types of activity you want to include in your feed.

at trunk 3.3 kB View raw
1import { describe, expect, it, vi } from 'vitest'; 2import type { Agent } from '@atproto/api'; 3import { fetchViewerProfile, displayNameFor, authorPath, accountMenuItems } from './profile'; 4 5/** Minimal Agent stub: only getProfile is exercised. */ 6function agentReturning( data: Record< string, unknown > ): Agent { 7 return { getProfile: vi.fn().mockResolvedValue( { data } ) } as unknown as Agent; 8} 9function agentThrowing(): Agent { 10 return { getProfile: vi.fn().mockRejectedValue( new Error( 'appview down' ) ) } as unknown as Agent; 11} 12 13describe( 'fetchViewerProfile', () => { 14 it( 'maps did, handle, displayName and avatar from getProfile', async () => { 15 const agent = agentReturning( { 16 did: 'did:plc:ignored', 17 handle: 'jane.bsky.social', 18 displayName: 'Jane Rivera', 19 avatar: 'https://cdn.example/av.jpg', 20 } ); 21 const profile = await fetchViewerProfile( agent, 'did:plc:abc' ); 22 expect( profile ).toEqual( { 23 did: 'did:plc:abc', 24 handle: 'jane.bsky.social', 25 displayName: 'Jane Rivera', 26 avatar: 'https://cdn.example/av.jpg', 27 } ); 28 } ); 29 30 it( 'falls back to nulls but keeps the did when getProfile throws', async () => { 31 const profile = await fetchViewerProfile( agentThrowing(), 'did:plc:abc' ); 32 expect( profile ).toEqual( { 33 did: 'did:plc:abc', 34 handle: null, 35 displayName: null, 36 avatar: null, 37 } ); 38 } ); 39 40 it( 'coerces missing optional fields to null', async () => { 41 const agent = agentReturning( { did: 'did:plc:abc', handle: 'jane.bsky.social' } ); 42 const profile = await fetchViewerProfile( agent, 'did:plc:abc' ); 43 expect( profile.displayName ).toBeNull(); 44 expect( profile.avatar ).toBeNull(); 45 expect( profile.handle ).toBe( 'jane.bsky.social' ); 46 } ); 47} ); 48 49describe( 'displayNameFor', () => { 50 const base = { did: 'did:plc:abc', handle: 'jane.bsky.social', avatar: null }; 51 it( 'prefers displayName', () => { 52 expect( displayNameFor( { ...base, displayName: 'Jane Rivera' } ) ).toBe( 'Jane Rivera' ); 53 } ); 54 it( 'falls back to handle when displayName is null', () => { 55 expect( displayNameFor( { ...base, displayName: null } ) ).toBe( 'jane.bsky.social' ); 56 } ); 57 it( 'falls back to the did when handle and displayName are null', () => { 58 expect( 59 displayNameFor( { did: 'did:plc:abc', handle: null, displayName: null, avatar: null } ) 60 ).toBe( 'did:plc:abc' ); 61 } ); 62} ); 63 64describe( 'authorPath', () => { 65 it( 'builds the public page path for a handle', () => { 66 expect( authorPath( 'jane.bsky.social' ) ).toBe( '/@jane.bsky.social' ); 67 } ); 68 it( 'returns null when there is no handle', () => { 69 expect( authorPath( null ) ).toBeNull(); 70 } ); 71} ); 72 73describe( 'accountMenuItems', () => { 74 const base = { did: 'did:plc:abc', displayName: 'Jane Rivera', avatar: null }; 75 76 it( 'returns Dashboard, Write and Profile in order for a profile with a handle', () => { 77 expect( accountMenuItems( { ...base, handle: 'jane.bsky.social' } ) ).toEqual( [ 78 { label: 'Dashboard', href: '/dashboard' }, 79 { label: 'Write', href: '/write' }, 80 { label: 'Profile', href: '/@jane.bsky.social' }, 81 ] ); 82 } ); 83 84 it( 'omits the Profile item when no handle is known', () => { 85 expect( accountMenuItems( { ...base, handle: null } ) ).toEqual( [ 86 { label: 'Dashboard', href: '/dashboard' }, 87 { label: 'Write', href: '/write' }, 88 ] ); 89 } ); 90} );