import { describe, expect, it } from 'vitest'; import type { SearchResults } from '../../api/subsonicTypes'; import { raceLiveSearch, type LiveSearchRaceSettled } from './searchRace'; const empty: SearchResults = { artists: [], albums: [], songs: [] }; const localHits: SearchResults = { artists: [{ id: 'a1', name: 'Local' }], albums: [], songs: [], }; const networkHits: SearchResults = { artists: [{ id: 'a2', name: 'Network' }], albums: [], songs: [], }; describe('raceLiveSearch', () => { it('network wins when it returns hits first', async () => { const winner = await raceLiveSearch( () => new Promise(resolve => { setTimeout(() => resolve(localHits), 40); }), async () => networkHits, () => false, ); expect(winner?.source).toBe('network'); }); it('waits for network when local is empty', async () => { const winner = await raceLiveSearch( async () => empty, async () => networkHits, () => false, ); expect(winner?.source).toBe('network'); }); it('local wins when network is empty and local has hits', async () => { const winner = await raceLiveSearch( async () => localHits, async () => empty, () => false, ); expect(winner?.source).toBe('local'); }); it('waits for local when network is empty', async () => { const winner = await raceLiveSearch( () => new Promise(resolve => { setTimeout(() => resolve(localHits), 30); }), async () => empty, () => false, ); expect(winner?.source).toBe('local'); }); it('does not pick empty local before network returns hits', async () => { const winner = await raceLiveSearch( async () => empty, () => new Promise(resolve => { setTimeout(() => resolve(networkHits), 30); }), () => false, ); expect(winner?.source).toBe('network'); }); it('calls onSettled with both runner timings', async () => { let settled: LiveSearchRaceSettled | null = null; await raceLiveSearch( async () => localHits, async () => networkHits, () => false, meta => { settled = meta; }, ); await new Promise(resolve => { setTimeout(resolve, 0); }); expect(settled).not.toBeNull(); expect(settled!.localHits).toBe('1/0/0'); expect(settled!.networkHits).toBe('1/0/0'); expect(settled!.localMs).toBeGreaterThanOrEqual(0); expect(settled!.networkMs).toBeGreaterThanOrEqual(0); }); });