import { describe, it, expect, vi, beforeEach } from 'vitest' import { AudioManager } from '../AudioManager.ts' const { HowlMock, HowlerMock, howlInstances } = vi.hoisted(() => { const howlInstances: any[] = [] const HowlMock = vi.fn(function (this: any, options: any) { const instance = { options, play: vi.fn(() => 1), pause: vi.fn(), stop: vi.fn(), fade: vi.fn(), unload: vi.fn(), } howlInstances.push(instance) return instance } as any) const HowlerMock = { volume: vi.fn(), } return { HowlMock, HowlerMock, howlInstances } }) vi.mock('howler', () => ({ Howl: HowlMock, Howler: HowlerMock, })) vi.mock('../../../binAssets.ts', () => ({ binAssetUrl: (path: string) => `https://assets.test/${path}`, })) beforeEach(() => { vi.clearAllMocks() howlInstances.length = 0 }) describe('AudioManager', () => { it('starts muted and lazy-loads soundtrack after unmute', () => { const audio = new AudioManager() expect(HowlerMock.volume).toHaveBeenLastCalledWith(0) expect(HowlMock).toHaveBeenCalledTimes(6) audio.startMusic() expect(HowlMock).toHaveBeenCalledTimes(6) audio.unmute() expect(HowlerMock.volume).toHaveBeenLastCalledWith(0.5) expect(HowlMock).toHaveBeenCalledTimes(7) expect(howlInstances[6].options.src[0]).toMatch(/music\/soundtrack\/bamboo_.*_32\.opus$/) expect(howlInstances[6].play).toHaveBeenCalled() }) it('mutes, unmutes, and destroys soundtrack separately from sfx', () => { const audio = new AudioManager() audio.startMusic() audio.unmute() const music = howlInstances[6] audio.mute() expect(HowlerMock.volume).toHaveBeenLastCalledWith(0) expect(music.pause).toHaveBeenCalledWith(1) audio.unmute() expect(music.play).toHaveBeenCalledTimes(2) audio.destroy() expect(howlInstances.slice(0, 4).every((howl) => howl.unload.mock.calls.length === 1)).toBe(true) expect(music.unload).toHaveBeenCalled() }) it('skips failed soundtrack tracks without throwing', () => { const audio = new AudioManager() audio.startMusic() audio.unmute() const firstMusic = howlInstances[6] expect(() => firstMusic.options.onloaderror()).not.toThrow() expect(firstMusic.unload).toHaveBeenCalled() expect(HowlMock).toHaveBeenCalledTimes(8) expect(howlInstances[7].play).toHaveBeenCalled() }) })