import { EventEmitter } from 'node:events'; import process from 'node:process'; import { VoiceConnectionStatus, type VoiceConnection } from '../src/VoiceConnection'; import { entersState } from '../src/util/entersState'; function createFakeVoiceConnection(status = VoiceConnectionStatus.Signalling) { const vc = new EventEmitter() as any; vc.state = { status }; return vc as VoiceConnection; } beforeEach(() => { jest.useFakeTimers(); }); describe('entersState', () => { test('Returns the target once the state has been entered before timeout', async () => { jest.useRealTimers(); const vc = createFakeVoiceConnection(); process.nextTick(() => vc.emit(VoiceConnectionStatus.Ready, null as any, null as any)); const result = await entersState(vc, VoiceConnectionStatus.Ready, 1_000); expect(result).toEqual(vc); }); test('Rejects once the timeout is exceeded', async () => { const vc = createFakeVoiceConnection(); const promise = entersState(vc, VoiceConnectionStatus.Ready, 1_000); jest.runAllTimers(); await expect(promise).rejects.toThrowError(); }); test('Returns the target once the state has been entered before signal is aborted', async () => { jest.useRealTimers(); const vc = createFakeVoiceConnection(); const ac = new AbortController(); process.nextTick(() => vc.emit(VoiceConnectionStatus.Ready, null as any, null as any)); const result = await entersState(vc, VoiceConnectionStatus.Ready, ac.signal); expect(result).toEqual(vc); }); test('Rejects once the signal is aborted', async () => { const vc = createFakeVoiceConnection(); const ac = new AbortController(); const promise = entersState(vc, VoiceConnectionStatus.Ready, ac.signal); ac.abort(); await expect(promise).rejects.toThrowError(); }); test('Resolves immediately when target already in desired state', async () => { const vc = createFakeVoiceConnection(); await expect(entersState(vc, VoiceConnectionStatus.Signalling, 1_000)).resolves.toEqual(vc); }); });