// End-to-end detection against a stubbed network, using the shapes real // publications are served with: a well-known endpoint that answers with a // handle-form at-uri, and a publication record whose `icon` is a path string // rather than a blob ref. Both shapes are real and neither is what the lexicon // suggests, which is why they are pinned here rather than in a live capture. import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { detectPage, dropProbes, wellKnownUrl } from './detection' const DID = 'did:plc:detectiontest0000000000' const URI = `at://${DID}/site.standard.publication/self` /** The backing map of the current chrome.storage.session stub, for assertions. */ let sessionStore = new Map() /** chrome.storage.session, which probeWellKnown uses as its probe cache. */ function stubChromeStorage() { const store = new Map() sessionStore = store vi.stubGlobal('chrome', { storage: { session: { get: async (key: string | null) => key === null ? Object.fromEntries(store) : store.has(key) ? { [key]: store.get(key) } : {}, set: async (items: Record) => { for (const [k, v] of Object.entries(items)) store.set(k, v) }, remove: async (keys: string | string[]) => { for (const k of [keys].flat()) store.delete(k) }, }, }, }) } function stubNetwork(record: Record) { const fetchMock = vi.fn(async (input: string) => { const url = String(input) if (url === 'https://pub.example/.well-known/site.standard.publication') { return new Response(`at://pub.example/site.standard.publication/self\n`) } if (url.includes('com.atproto.identity.resolveHandle')) { return new Response(JSON.stringify({ did: DID })) } if (url === `https://plc.directory/${DID}`) { return new Response( JSON.stringify({ alsoKnownAs: ['at://pub.example'], service: [ { id: '#atproto_pds', type: 'AtprotoPersonalDataServer', serviceEndpoint: 'https://pds.example.com', }, ], }), ) } if (url.includes('com.atproto.repo.getRecord')) { return new Response(JSON.stringify({ uri: URI, cid: 'bafcid', value: record })) } return new Response('not found', { status: 404, statusText: 'Not Found' }) }) vi.stubGlobal('fetch', fetchMock) return fetchMock } const baseRecord = { $type: 'site.standard.publication', url: 'https://pub.example', name: 'Detection Fixture', description: 'wobbegong', } beforeEach(stubChromeStorage) afterEach(() => { vi.unstubAllGlobals() }) describe('detectPage', () => { it('verifies a publication whose well-known returns a handle-form at-uri', async () => { stubNetwork(baseRecord) const { pub } = await detectPage('https://pub.example/') expect(pub?.uri).toBe(URI) expect(pub?.verified).toBe(true) expect(pub?.handle).toBe('pub.example') expect(pub?.iconUrl).toBeUndefined() }) it('builds an icon url from a real blob ref', async () => { stubNetwork({ ...baseRecord, icon: { $type: 'blob', ref: { $link: 'bafkreiicon' }, mimeType: 'image/png', size: 9 }, }) const { pub } = await detectPage('https://pub.example/') expect(pub?.iconUrl).toBe( `https://pds.example.com/xrpc/com.atproto.sync.getBlob?did=${encodeURIComponent(DID)}&cid=bafkreiicon`, ) }) it('still detects when the record puts a path string in `icon`', async () => { // Regression: reading blob.ref.$link off a string threw, and the throw // surfaced as a fetch-failed error instead of a detected publication. stubNetwork({ ...baseRecord, icon: '/assets/images/favicon/apple-touch-icon.png' }) const { pub } = await detectPage('https://pub.example/') expect(pub?.verified).toBe(true) expect(pub?.iconUrl).toBeUndefined() }) }) /** Counts well-known probes and answers every one of them with a miss. */ function missingWellKnown() { const fetchSpy = vi.fn(async () => new Response('', { status: 404, statusText: 'Not Found' })) vi.stubGlobal('fetch', fetchSpy) return fetchSpy } describe('wellKnownUrl', () => { it('probes the origin for a root publication', () => { expect(wellKnownUrl('https://example.test')).toBe( 'https://example.test/.well-known/site.standard.publication', ) }) it('ignores a trailing slash', () => { expect(wellKnownUrl('https://example.test/')).toBe( 'https://example.test/.well-known/site.standard.publication', ) }) // atproto.com/blog is a real publication of this shape: the origin 404s and // only the path-suffixed probe answers. it('appends the base path for a publication below the root', () => { expect(wellKnownUrl('https://atproto.test/blog')).toBe( 'https://atproto.test/.well-known/site.standard.publication/blog', ) }) it('drops query and fragment', () => { expect(wellKnownUrl('https://example.test/blog?x=1#y')).toBe( 'https://example.test/.well-known/site.standard.publication/blog', ) }) }) describe('well-known probe caching', () => { it('asks an origin once and serves later pages under it from cache', async () => { const fetchSpy = missingWellKnown() await detectPage('https://example.test/blog/one') const afterFirst = fetchSpy.mock.calls.length await detectPage('https://example.test/blog/two') await detectPage('https://example.test/blog/three') expect(fetchSpy.mock.calls.length).toBe(afterFirst) }) // The Refresh button existed but could not do the one thing it is for: a // publisher fixing their well-known kept seeing the cached miss. it('re-asks the origin when the caller forces a refresh', async () => { const fetchSpy = missingWellKnown() await detectPage('https://example.test/one') const afterFirst = fetchSpy.mock.calls.length await detectPage('https://example.test/one', undefined, undefined, true) expect(fetchSpy.mock.calls.length).toBeGreaterThan(afterFirst) }) it('collapses concurrent probes of one origin into a single request', async () => { const fetchSpy = missingWellKnown() await Promise.all([ detectPage('https://example.test/a'), detectPage('https://example.test/b'), detectPage('https://example.test/c'), ]) // Origin probe plus the one path-level probe each page triggers on a miss; // without dedupe this would be three times as many. expect(fetchSpy.mock.calls.length).toBeLessThanOrEqual(4) }) it('records a miss so a second visit does not re-ask', async () => { missingWellKnown() await detectPage('https://example.test/one') const keys = [...sessionStore.keys()].filter((k) => k.startsWith('wk:')) expect(keys.length).toBeGreaterThan(0) expect(sessionStore.get(keys[0]!)).toMatchObject({ uri: null }) }) // The dev build's Drop cache: this cache is the one nothing else empties, // since Refresh only bypasses it for the page it is walking. it('re-asks every origin after the probe answers are dropped', async () => { const fetchSpy = missingWellKnown() await detectPage('https://example.test/one') const afterFirst = fetchSpy.mock.calls.length expect(await dropProbes()).toBeGreaterThan(0) expect([...sessionStore.keys()].filter((k) => k.startsWith('wk:'))).toEqual([]) await detectPage('https://example.test/one') expect(fetchSpy.mock.calls.length).toBeGreaterThan(afterFirst) }) it('leaves everything that is not a probe answer alone', async () => { missingWellKnown() // A per-tab detection state: the worker's, dropped by the worker, and not // something a sweep of this cache may take with it. sessionStore.set('tab:7', { url: 'https://example.test/one' }) await detectPage('https://example.test/one') await dropProbes() expect(sessionStore.get('tab:7')).toEqual({ url: 'https://example.test/one' }) }) it('reports no publication rather than throwing when every probe misses', async () => { missingWellKnown() await expect(detectPage('https://example.test/one')).resolves.toEqual({ pub: undefined, doc: undefined, }) }) /** * Documents a real cost rather than asserting a wish: on an origin with no * publication, each new *first path segment* earns its own probe, because a * publication may legitimately live under one path and not another. See * TODO.md — narrowing this needs a heuristic with false negatives. */ it('probes each distinct first path segment on an origin with no publication', async () => { const fetchSpy = missingWellKnown() await detectPage('https://example.test/one') const afterFirst = fetchSpy.mock.calls.length await detectPage('https://example.test/two') expect(fetchSpy.mock.calls.length).toBe(afterFirst + 1) }) })