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 4.3 kB View raw
1import { describe, expect, it, vi, beforeEach } from 'vitest'; 2import { listAllReaderPublications } from './publications'; 3import { listRecords } from './records'; 4import { SITE_BASE } from '../publish/records'; 5import { THEME_PRESETS } from '../publish/themes'; 6 7vi.mock( './records', () => ( { listRecords: vi.fn() } ) ); 8const mockedList = listRecords as unknown as ReturnType< typeof vi.fn >; 9 10const PDS = 'https://pds.example'; 11const DID = 'did:plc:me'; 12 13function rec( rkey: string, url: string, extra: Record< string, unknown > = {} ) { 14 return { uri: `at://${ DID }/site.standard.publication/${ rkey }`, cid: 'c', value: { url, name: `P${ rkey }`, ...extra } }; 15} 16 17beforeEach( () => mockedList.mockReset() ); 18 19describe( 'listAllReaderPublications', () => { 20 it( 'keeps only SkyPress-origin, slugged publications as owned', async () => { 21 mockedList.mockResolvedValue( [ 22 rec( 'a', `${ SITE_BASE }/@me.bsky.social/blog`, { description: ' Hi ' } ), 23 rec( 'b', 'https://leaflet.pub/x/y' ), 24 rec( 'c', `${ SITE_BASE }/@me.bsky.social` ), 25 ] ); 26 const { owned } = await listAllReaderPublications( PDS, DID ); 27 expect( owned ).toHaveLength( 1 ); 28 expect( owned[ 0 ] ).toMatchObject( { 29 uri: `at://${ DID }/site.standard.publication/a`, 30 slug: 'blog', 31 name: 'Pa', 32 description: 'Hi', 33 } ); 34 } ); 35 36 it( 'partitions owned SkyPress publications from foreign ones', async () => { 37 const icon = { ref: { $link: 'bafyicon' }, mimeType: 'image/png', size: 1 }; 38 mockedList.mockResolvedValue( [ 39 rec( 'a', `${ SITE_BASE }/@me.bsky.social/blog`, { description: ' Hi ' } ), 40 rec( 'b', 'https://leaflet.pub/lish/did:plc:me/xyz', { name: 'My Leaflet', icon } ), 41 rec( 'c', 'ipfs://not-a-web-url' ), // non-http(s) → excluded everywhere 42 rec( 'd', `${ SITE_BASE }/@me.bsky.social` ), // SkyPress, no slug → dropped 43 ] ); 44 const { owned, foreign } = await listAllReaderPublications( PDS, DID ); 45 46 expect( owned ).toHaveLength( 1 ); 47 expect( owned[ 0 ] ).toMatchObject( { slug: 'blog', name: 'Pa' } ); 48 49 expect( foreign ).toHaveLength( 1 ); 50 expect( foreign[ 0 ] ).toEqual( { 51 uri: `at://${ DID }/site.standard.publication/b`, 52 name: 'My Leaflet', 53 hostname: 'leaflet.pub', 54 url: 'https://leaflet.pub/lish/did:plc:me/xyz', 55 icon, 56 provider: 'leaflet', 57 } ); 58 } ); 59 60 it( 'tags each foreign publication with its hostname and detected provider', async () => { 61 mockedList.mockResolvedValue( [ 62 rec( 'a', 'https://jehervecom.leaflet.pub' ), 63 rec( 'b', 'https://my-domain.example', { theme: { $type: 'blog.pckt.theme' } } ), 64 rec( 'c', 'https://unknown.example/path' ), 65 ] ); 66 const { foreign } = await listAllReaderPublications( PDS, DID ); 67 const byRkey = Object.fromEntries( 68 foreign.map( ( p ) => [ p.uri.split( '/' ).pop(), { hostname: p.hostname, provider: p.provider } ] ) 69 ); 70 expect( byRkey ).toEqual( { 71 a: { hostname: 'jehervecom.leaflet.pub', provider: 'leaflet' }, 72 b: { hostname: 'my-domain.example', provider: 'pckt' }, 73 c: { hostname: 'unknown.example', provider: null }, 74 } ); 75 } ); 76 77 it( 'falls back to the hostname when a foreign record has no name', async () => { 78 mockedList.mockResolvedValue( [ 79 { uri: `at://${ DID }/site.standard.publication/n`, cid: 'c', value: { url: 'https://leaflet.pub/x' } }, 80 ] ); 81 const { foreign } = await listAllReaderPublications( PDS, DID ); 82 expect( foreign[ 0 ] ).toMatchObject( { name: 'leaflet.pub', icon: null } ); 83 } ); 84} ); 85 86describe( 'reader basicTheme', () => { 87 it( 'surfaces a valid stored basicTheme', async () => { 88 mockedList.mockResolvedValue( [ 89 rec( 'a', `${ SITE_BASE }/@me.bsky.social/blog`, { 90 basicTheme: THEME_PRESETS[ 5 ].colors, // morning 91 } ), 92 ] ); 93 const { owned } = await listAllReaderPublications( PDS, DID ); 94 expect( owned[ 0 ].basicTheme ).toEqual( THEME_PRESETS[ 5 ].colors ); 95 } ); 96 97 it( 'sets basicTheme to null when absent or malformed', async () => { 98 mockedList.mockResolvedValue( [ 99 rec( 'a', `${ SITE_BASE }/@me.bsky.social/plain` ), 100 rec( 'b', `${ SITE_BASE }/@me.bsky.social/broken`, { basicTheme: { accent: 'red' } } ), 101 ] ); 102 const { owned } = await listAllReaderPublications( PDS, DID ); 103 expect( owned.find( ( p ) => p.slug === 'plain' )?.basicTheme ).toBeNull(); 104 expect( owned.find( ( p ) => p.slug === 'broken' )?.basicTheme ).toBeNull(); 105 } ); 106} );