feat: enhance discovery, vibe sessions, and library enrichment
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import type { Track } from '../types';
|
||||
import { usePlaybackStore } from '../store/usePlaybackStore';
|
||||
import { useVibeStore } from '../store/useVibeStore';
|
||||
|
||||
const { next, start } = vi.hoisted(() => ({ next: vi.fn(), start: vi.fn() }));
|
||||
vi.mock('./vibeService', () => ({
|
||||
vibeService: { start, next },
|
||||
fetchNextBatch: async (count: number, sessionId: string) => {
|
||||
const tracks: Track[] = [];
|
||||
for (let index = 0; index < count; index++) {
|
||||
try { tracks.push((await next(sessionId)).track); } catch { return { tracks, status: 'failed' as const }; }
|
||||
}
|
||||
return { tracks, status: 'complete' as const };
|
||||
},
|
||||
}));
|
||||
|
||||
import { startVibeSession } from './vibeSession';
|
||||
|
||||
const track = (id: string): Track => ({
|
||||
id, path: `/music/${id}.mp3`, hash: id, title: id, artist: 'Artist',
|
||||
album_id: 'album', duration: 180, state: 'LIBRARY', source_type: 'MANUAL',
|
||||
play_count: 0, skip_count: 0, dislike_count: 0,
|
||||
});
|
||||
|
||||
describe('startVibeSession', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
useVibeStore.getState().reset();
|
||||
usePlaybackStore.setState({ currentTrack: null, queue: [], currentIndex: -1, isPlaying: false });
|
||||
});
|
||||
|
||||
it('does not replace a working Vibe when the new plan cannot hydrate', async () => {
|
||||
const old = track('old');
|
||||
useVibeStore.getState().setActiveSession({ sessionId: 'old-session', seedTrackId: old.id });
|
||||
usePlaybackStore.getState().setQueue([old]);
|
||||
usePlaybackStore.getState().playTrack(old);
|
||||
start.mockResolvedValue({ sessionId: 'new-session', plan: [] });
|
||||
next.mockRejectedValue(new Error('missing session'));
|
||||
|
||||
await expect(startVibeSession(track('seed'))).resolves.toMatchObject({ tracks: [], status: 'failed' });
|
||||
expect(useVibeStore.getState().activeSessionId).toBe('old-session');
|
||||
expect(usePlaybackStore.getState().currentTrack?.id).toBe('old');
|
||||
});
|
||||
|
||||
it('serializes rapid starts and hydrates only one session', async () => {
|
||||
const recommended = track('recommended');
|
||||
start.mockResolvedValue({ sessionId: 'session-a', plan: [] });
|
||||
next.mockResolvedValue({ track: recommended });
|
||||
|
||||
await Promise.all([startVibeSession(track('seed-a')), startVibeSession(track('seed-b'))]);
|
||||
expect(start).toHaveBeenCalledTimes(1);
|
||||
expect(next).toHaveBeenCalledWith('session-a');
|
||||
expect(useVibeStore.getState().activeSessionId).toBe('session-a');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user