import { describe, it, expect, vi, beforeEach } from 'vitest' import { useAudioPlayer } from '../useAudioPlayer' // Mock HTMLAudioElement class MockAudio { src = '' currentTime = 0 duration = 120 paused = true private listeners: Record void>> = {} addEventListener(event: string, handler: () => void) { if (!this.listeners[event]) this.listeners[event] = [] this.listeners[event].push(handler) } removeEventListener() { // no-op for tests } play() { this.paused = false this.emit('play') return Promise.resolve() } pause() { this.paused = true this.emit('pause') } private emit(event: string) { const handlers = this.listeners[event] || [] handlers.forEach(h => h()) } // Helper to simulate events in tests simulateEvent(event: string) { this.emit(event) } } vi.stubGlobal('Audio', MockAudio) describe('useAudioPlayer', () => { beforeEach(() => { // Reset singleton state by stopping any active playback const player = useAudioPlayer() player.stop() }) it('returns all expected properties', () => { const player = useAudioPlayer() expect(player.play).toBeTypeOf('function') expect(player.pause).toBeTypeOf('function') expect(player.seek).toBeTypeOf('function') expect(player.stop).toBeTypeOf('function') expect(player.playing).toBeDefined() expect(player.currentName).toBeDefined() expect(player.currentTime).toBeDefined() expect(player.duration).toBeDefined() expect(player.progress).toBeDefined() expect(player.currentSrc).toBeDefined() expect(player.error).toBeDefined() }) it('starts in stopped state', () => { const player = useAudioPlayer() expect(player.playing.value).toBe(false) expect(player.currentSrc.value).toBeNull() expect(player.currentName.value).toBe('') }) it('play sets playing state and current source', () => { const player = useAudioPlayer() player.play('/audio/test.mp3', 'Test Track') expect(player.playing.value).toBe(true) expect(player.currentSrc.value).toBe('/audio/test.mp3') expect(player.currentName.value).toBe('Test Track') }) it('play toggles pause when same source is playing', () => { const player = useAudioPlayer() player.play('/audio/test.mp3', 'Test') expect(player.playing.value).toBe(true) // Play same source again — should pause player.play('/audio/test.mp3', 'Test') expect(player.playing.value).toBe(false) }) it('play switches to new source', () => { const player = useAudioPlayer() player.play('/audio/first.mp3', 'First') player.play('/audio/second.mp3', 'Second') expect(player.currentSrc.value).toBe('/audio/second.mp3') expect(player.currentName.value).toBe('Second') }) it('pause pauses playback', () => { const player = useAudioPlayer() player.play('/audio/test.mp3', 'Test') player.pause() expect(player.playing.value).toBe(false) }) it('stop resets all state', () => { const player = useAudioPlayer() player.play('/audio/test.mp3', 'Test') player.stop() expect(player.playing.value).toBe(false) expect(player.currentSrc.value).toBeNull() expect(player.currentName.value).toBe('') }) it('progress computes correctly', () => { const player = useAudioPlayer() expect(player.progress.value).toBe(0) // duration is 0 player.currentTime.value = 30 player.duration.value = 120 expect(player.progress.value).toBe(25) // 30/120 * 100 }) it('progress is 0 when duration is 0', () => { const player = useAudioPlayer() player.duration.value = 0 player.currentTime.value = 10 expect(player.progress.value).toBe(0) }) it('shared state across multiple useAudioPlayer calls', () => { const p1 = useAudioPlayer() const p2 = useAudioPlayer() p1.play('/audio/shared.mp3', 'Shared') expect(p2.currentSrc.value).toBe('/audio/shared.mp3') expect(p2.playing.value).toBe(true) }) })