import { vi } from 'vitest'; /** * Подставной `Audio` для тестов саундборда: в jsdom `play()` не реализован, * поэтому звук подменяется целиком. Экземпляры собираются в массив — по ним * проверяют, что звук скачали, проиграли или остановили. */ export class FakeAudio { src: string; volume = 1; currentTime = 0; paused = true; playCalls = 0; pauseCalls = 0; /** Считаем и нативные, и «событийные» подписки: `ended` глушит звук. */ readonly listeners = new Map void>>(); constructor(src = '') { this.src = src; } addEventListener(type: string, handler: () => void): void { const set = this.listeners.get(type) ?? new Set<() => void>(); set.add(handler); this.listeners.set(type, set); } removeEventListener(type: string, handler: () => void): void { this.listeners.get(type)?.delete(handler); } play(): Promise { this.playCalls += 1; this.paused = false; return Promise.resolve(); } pause(): void { this.pauseCalls += 1; this.paused = true; } /** Сообщить о конце звука: движок снимает элемент с учёта. */ emit(type: string): void { for (const handler of [...(this.listeners.get(type) ?? [])]) { handler(); } } } /** Ставит подставной `Audio` и возвращает список созданных элементов. */ export function installFakeAudio(): FakeAudio[] { const instances: FakeAudio[] = []; class StubAudio extends FakeAudio { constructor(src = '') { super(src); instances.push(this); } } vi.stubGlobal('Audio', StubAudio); return instances; }