test: replace jest with vitest (#10472)

* chore: vitest config

* feat: vitest

* fix: do not actually create ws

* chore: config

* chore: lockfile

* chore: revert downgrade, up node

* chore: package - 'git add -A'

* chore: delete mock-socket

* chore: delete mock-socket

* fix: lockfile

---------

Co-authored-by: almeidx <github@almeidx.dev>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
pat
2024-10-07 01:26:53 +11:00
committed by GitHub
parent bb04e09f8b
commit 24128a3c45
21 changed files with 267 additions and 219 deletions

View File

@@ -5,6 +5,7 @@ import { Buffer } from 'node:buffer';
import { once } from 'node:events';
import process from 'node:process';
import { Readable } from 'node:stream';
import { describe, test, expect, vitest, type Mock, beforeEach, afterEach } from 'vitest';
import { addAudioPlayer, deleteAudioPlayer } from '../src/DataStore';
import { VoiceConnection, VoiceConnectionStatus } from '../src/VoiceConnection';
import type { AudioPlayer } from '../src/audio/AudioPlayer';
@@ -13,14 +14,31 @@ import { AudioPlayerError } from '../src/audio/AudioPlayerError';
import { AudioResource } from '../src/audio/AudioResource';
import { NoSubscriberBehavior } from '../src/index';
jest.mock('../src/DataStore');
jest.mock('../src/VoiceConnection');
jest.mock('../src/audio/AudioPlayerError');
vitest.mock('../src/DataStore', () => {
return {
addAudioPlayer: vitest.fn(),
deleteAudioPlayer: vitest.fn(),
};
});
const addAudioPlayerMock = addAudioPlayer as unknown as jest.Mock<typeof addAudioPlayer>;
const deleteAudioPlayerMock = deleteAudioPlayer as unknown as jest.Mock<typeof deleteAudioPlayer>;
const AudioPlayerErrorMock = AudioPlayerError as unknown as jest.Mock<typeof AudioPlayerError>;
const VoiceConnectionMock = VoiceConnection as unknown as jest.Mock<VoiceConnection>;
vitest.mock('../src/VoiceConnection', async (importOriginal) => {
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
const actual = await importOriginal<typeof import('../src/VoiceConnection')>();
const VoiceConnection = vitest.fn();
VoiceConnection.prototype.setSpeaking = vitest.fn();
VoiceConnection.prototype.dispatchAudio = vitest.fn();
VoiceConnection.prototype.prepareAudioPacket = vitest.fn();
return {
...actual,
VoiceConnection,
};
});
vitest.mock('../src/audio/AudioPlayerError', () => {
return {
AudioPlayerError: vitest.fn(),
};
});
function* silence() {
while (true) {
@@ -29,15 +47,15 @@ function* silence() {
}
function createVoiceConnectionMock() {
const connection = new VoiceConnectionMock();
const connection = new VoiceConnection({} as any, {} as any);
connection.state = {
status: VoiceConnectionStatus.Signalling,
adapter: {
sendPayload: jest.fn(),
destroy: jest.fn(),
sendPayload: vitest.fn(),
destroy: vitest.fn(),
},
};
connection.subscribe = jest.fn((player) => player['subscribe'](connection));
connection.subscribe = vitest.fn((player) => player['subscribe'](connection));
return connection;
}
@@ -57,10 +75,7 @@ async function started(resource: AudioResource) {
let player: AudioPlayer | undefined;
beforeEach(() => {
AudioPlayerErrorMock.mockReset();
VoiceConnectionMock.mockReset();
addAudioPlayerMock.mockReset();
deleteAudioPlayerMock.mockReset();
vitest.resetAllMocks();
});
afterEach(() => {
@@ -71,8 +86,8 @@ describe('State transitions', () => {
test('Starts in Idle state', () => {
player = createAudioPlayer();
expect(player.state.status).toEqual(AudioPlayerStatus.Idle);
expect(addAudioPlayerMock).toBeCalledTimes(0);
expect(deleteAudioPlayerMock).toBeCalledTimes(0);
expect(addAudioPlayer).toBeCalledTimes(0);
expect(deleteAudioPlayer).toBeCalledTimes(0);
});
test('Playing resource with pausing and resuming', async () => {
@@ -86,11 +101,11 @@ describe('State transitions', () => {
expect(player.state.status).toEqual(AudioPlayerStatus.Idle);
expect(player.unpause()).toEqual(false);
expect(player.state.status).toEqual(AudioPlayerStatus.Idle);
expect(addAudioPlayerMock).toBeCalledTimes(0);
expect(addAudioPlayer).toBeCalledTimes(0);
player.play(resource);
expect(player.state.status).toEqual(AudioPlayerStatus.Playing);
expect(addAudioPlayerMock).toBeCalledTimes(1);
expect(addAudioPlayer).toBeCalledTimes(1);
// Expect pause() to return true and transition to paused state
expect(player.pause()).toEqual(true);
@@ -109,7 +124,7 @@ describe('State transitions', () => {
expect(player.state.status).toEqual(AudioPlayerStatus.Playing);
// The audio player should not have been deleted throughout these changes
expect(deleteAudioPlayerMock).toBeCalledTimes(0);
expect(deleteAudioPlayer).toBeCalledTimes(0);
});
test('Playing to Stopping', async () => {
@@ -122,13 +137,13 @@ describe('State transitions', () => {
player.play(resource);
expect(player.state.status).toEqual(AudioPlayerStatus.Playing);
expect(addAudioPlayerMock).toBeCalledTimes(1);
expect(deleteAudioPlayerMock).toBeCalledTimes(0);
expect(addAudioPlayer).toBeCalledTimes(1);
expect(deleteAudioPlayer).toBeCalledTimes(0);
expect(player.stop()).toEqual(true);
expect(player.state.status).toEqual(AudioPlayerStatus.Playing);
expect(addAudioPlayerMock).toBeCalledTimes(1);
expect(deleteAudioPlayerMock).toBeCalledTimes(0);
expect(addAudioPlayer).toBeCalledTimes(1);
expect(deleteAudioPlayer).toBeCalledTimes(0);
expect(resource.silenceRemaining).toEqual(5);
});
@@ -142,8 +157,8 @@ describe('State transitions', () => {
await started(resource);
expect(player.state.status).toEqual(AudioPlayerStatus.Playing);
expect(addAudioPlayerMock).toHaveBeenCalled();
expect(deleteAudioPlayerMock).not.toHaveBeenCalled();
expect(addAudioPlayer).toHaveBeenCalled();
expect(deleteAudioPlayer).not.toHaveBeenCalled();
});
describe('NoSubscriberBehavior transitions', () => {
@@ -188,11 +203,11 @@ describe('State transitions', () => {
player = createAudioPlayer({ behaviors: { noSubscriber: NoSubscriberBehavior.Stop } });
player.play(resource);
expect(addAudioPlayerMock).toBeCalledTimes(1);
expect(addAudioPlayer).toBeCalledTimes(1);
expect(player.checkPlayable()).toEqual(true);
player['_stepPrepare']();
expect(player.state.status).toEqual(AudioPlayerStatus.Idle);
expect(deleteAudioPlayerMock).toBeCalledTimes(1);
expect(deleteAudioPlayer).toBeCalledTimes(1);
});
});
@@ -217,7 +232,7 @@ describe('State transitions', () => {
player.play(resource);
expect(player.state.status).toEqual(AudioPlayerStatus.Playing);
expect(addAudioPlayerMock).toBeCalledTimes(1);
expect(addAudioPlayer).toBeCalledTimes(1);
expect(player.checkPlayable()).toEqual(true);
// Run through a few packet cycles
@@ -241,7 +256,8 @@ describe('State transitions', () => {
expect(connection.dispatchAudio).toHaveBeenCalledTimes(6);
await wait();
player['_stepPrepare']();
const prepareAudioPacket = connection.prepareAudioPacket as unknown as jest.Mock<
const prepareAudioPacket = connection.prepareAudioPacket as unknown as Mock<
[Buffer],
typeof connection.prepareAudioPacket
>;
expect(prepareAudioPacket).toHaveBeenCalledTimes(6);
@@ -251,7 +267,7 @@ describe('State transitions', () => {
expect(player.state.status).toEqual(AudioPlayerStatus.Idle);
expect(connection.setSpeaking).toBeCalledTimes(1);
expect(connection.setSpeaking).toHaveBeenLastCalledWith(false);
expect(deleteAudioPlayerMock).toHaveBeenCalledTimes(1);
expect(deleteAudioPlayer).toHaveBeenCalledTimes(1);
});
test('stop() causes resource to use silence padding frames', async () => {
@@ -275,7 +291,7 @@ describe('State transitions', () => {
player.play(resource);
expect(player.state.status).toEqual(AudioPlayerStatus.Playing);
expect(addAudioPlayerMock).toBeCalledTimes(1);
expect(addAudioPlayer).toBeCalledTimes(1);
expect(player.checkPlayable()).toEqual(true);
player.stop();
@@ -298,7 +314,8 @@ describe('State transitions', () => {
await wait();
expect(player.checkPlayable()).toEqual(false);
const prepareAudioPacket = connection.prepareAudioPacket as unknown as jest.Mock<
const prepareAudioPacket = connection.prepareAudioPacket as unknown as Mock<
[Buffer],
typeof connection.prepareAudioPacket
>;
expect(prepareAudioPacket).toHaveBeenCalledTimes(5);
@@ -306,7 +323,7 @@ describe('State transitions', () => {
expect(player.state.status).toEqual(AudioPlayerStatus.Idle);
expect(connection.setSpeaking).toBeCalledTimes(1);
expect(connection.setSpeaking).toHaveBeenLastCalledWith(false);
expect(deleteAudioPlayerMock).toHaveBeenCalledTimes(1);
expect(deleteAudioPlayer).toHaveBeenCalledTimes(1);
});
test('Plays silence 5 times for unreadable stream before quitting', async () => {
@@ -328,10 +345,11 @@ describe('State transitions', () => {
player.play(resource);
expect(player.state.status).toEqual(AudioPlayerStatus.Playing);
expect(addAudioPlayerMock).toBeCalledTimes(1);
expect(addAudioPlayer).toBeCalledTimes(1);
expect(player.checkPlayable()).toEqual(true);
const prepareAudioPacket = connection.prepareAudioPacket as unknown as jest.Mock<
const prepareAudioPacket = connection.prepareAudioPacket as unknown as Mock<
[Buffer],
typeof connection.prepareAudioPacket
>;
@@ -351,7 +369,7 @@ describe('State transitions', () => {
expect(player.state.status).toEqual(AudioPlayerStatus.Idle);
expect(connection.setSpeaking).toBeCalledTimes(1);
expect(connection.setSpeaking).toHaveBeenLastCalledWith(false);
expect(deleteAudioPlayerMock).toHaveBeenCalledTimes(1);
expect(deleteAudioPlayer).toHaveBeenCalledTimes(1);
});
test('checkPlayable() transitions to Idle for unreadable stream', async () => {
@@ -397,6 +415,6 @@ test('Propagates errors from streams', async () => {
const res = await once(player, 'error');
const playerError = res[0] as AudioPlayerError;
expect(playerError).toBeInstanceOf(AudioPlayerError);
expect(AudioPlayerErrorMock).toHaveBeenCalledWith(error, resource);
expect(AudioPlayerError).toHaveBeenCalledWith(error, resource);
expect(player.state.status).toEqual(AudioPlayerStatus.Idle);
});