refactor: use eslint-config-neon for packages. (#8579)

Co-authored-by: Noel <buechler.noel@outlook.com>
This commit is contained in:
Suneet Tipirneni
2022-09-01 14:50:16 -04:00
committed by GitHub
parent 4bdb0593ae
commit edadb9fe5d
219 changed files with 2608 additions and 2053 deletions

View File

@@ -1,14 +1,17 @@
/* eslint-disable @typescript-eslint/unbound-method */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/dot-notation */
import { Buffer } from 'node:buffer';
import { once } from 'node:events';
import process from 'node:process';
import { Readable } from 'node:stream';
import { NoSubscriberBehavior } from '../src';
import { addAudioPlayer, deleteAudioPlayer } from '../src/DataStore';
import { VoiceConnection, VoiceConnectionStatus } from '../src/VoiceConnection';
import { createAudioPlayer, AudioPlayerStatus, AudioPlayer, SILENCE_FRAME } from '../src/audio/AudioPlayer';
import { createAudioPlayer, AudioPlayerStatus, SILENCE_FRAME, type AudioPlayerState } from '../src/audio/AudioPlayer';
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');
@@ -39,7 +42,8 @@ function createVoiceConnectionMock() {
return connection;
}
function wait() {
async function wait() {
// eslint-disable-next-line no-promise-executor-return
return new Promise((resolve) => process.nextTick(resolve));
}
@@ -47,6 +51,7 @@ async function started(resource: AudioResource) {
while (!resource.started) {
await wait();
}
return resource;
}
@@ -197,6 +202,7 @@ describe('State transitions', () => {
if (connection.state.status !== VoiceConnectionStatus.Signalling) {
throw new Error('Voice connection should have been Signalling');
}
connection.state = {
...connection.state,
status: VoiceConnectionStatus.Ready,
@@ -216,18 +222,18 @@ describe('State transitions', () => {
expect(player.checkPlayable()).toEqual(true);
// Run through a few packet cycles
for (let i = 1; i <= 5; i++) {
for (let index = 1; index <= 5; index++) {
player['_stepDispatch']();
expect(connection.dispatchAudio).toHaveBeenCalledTimes(i);
expect(connection.dispatchAudio).toHaveBeenCalledTimes(index);
await wait(); // Wait for the stream
player['_stepPrepare']();
expect(connection.prepareAudioPacket).toHaveBeenCalledTimes(i);
expect(connection.prepareAudioPacket).toHaveBeenCalledTimes(index);
expect(connection.prepareAudioPacket).toHaveBeenLastCalledWith(buffer);
expect(player.state.status).toEqual(AudioPlayerStatus.Playing);
if (player.state.status === AudioPlayerStatus.Playing) {
expect(player.state.playbackDuration).toStrictEqual(i * 20);
expect(player.state.playbackDuration).toStrictEqual(index * 20);
}
}
@@ -254,6 +260,7 @@ describe('State transitions', () => {
if (connection.state.status !== VoiceConnectionStatus.Signalling) {
throw new Error('Voice connection should have been Signalling');
}
connection.state = {
...connection.state,
status: VoiceConnectionStatus.Ready,
@@ -275,20 +282,21 @@ describe('State transitions', () => {
player.stop();
// Run through a few packet cycles
for (let i = 1; i <= 5; i++) {
for (let index = 1; index <= 5; index++) {
player['_stepDispatch']();
expect(connection.dispatchAudio).toHaveBeenCalledTimes(i);
expect(connection.dispatchAudio).toHaveBeenCalledTimes(index);
await wait(); // Wait for the stream
player['_stepPrepare']();
expect(connection.prepareAudioPacket).toHaveBeenCalledTimes(i);
expect(connection.prepareAudioPacket).toHaveBeenCalledTimes(index);
expect(connection.prepareAudioPacket).toHaveBeenLastCalledWith(SILENCE_FRAME);
expect(player.state.status).toEqual(AudioPlayerStatus.Playing);
if (player.state.status === AudioPlayerStatus.Playing) {
expect(player.state.playbackDuration).toStrictEqual(i * 20);
expect(player.state.playbackDuration).toStrictEqual(index * 20);
}
}
await wait();
expect(player.checkPlayable()).toEqual(false);
const prepareAudioPacket = connection.prepareAudioPacket as unknown as jest.Mock<
@@ -307,6 +315,7 @@ describe('State transitions', () => {
if (connection.state.status !== VoiceConnectionStatus.Signalling) {
throw new Error('Voice connection should have been Signalling');
}
connection.state = {
...connection.state,
status: VoiceConnectionStatus.Ready,
@@ -328,16 +337,16 @@ describe('State transitions', () => {
>;
// Run through a few packet cycles
for (let i = 1; i <= 5; i++) {
for (let index = 1; index <= 5; index++) {
expect(player.state.status).toEqual(AudioPlayerStatus.Playing);
if (player.state.status !== AudioPlayerStatus.Playing) throw new Error('Error');
expect(player.state.playbackDuration).toStrictEqual((i - 1) * 20);
expect(player.state.missedFrames).toEqual(i - 1);
expect(player.state.playbackDuration).toStrictEqual((index - 1) * 20);
expect(player.state.missedFrames).toEqual(index - 1);
player['_stepDispatch']();
expect(connection.dispatchAudio).toHaveBeenCalledTimes(i);
expect(connection.dispatchAudio).toHaveBeenCalledTimes(index);
player['_stepPrepare']();
expect(prepareAudioPacket).toHaveBeenCalledTimes(i);
expect(prepareAudioPacket.mock.calls[i - 1][0]).toEqual(silence().next().value);
expect(prepareAudioPacket).toHaveBeenCalledTimes(index);
expect(prepareAudioPacket.mock.calls[index - 1][0]).toEqual(silence().next().value);
}
expect(player.state.status).toEqual(AudioPlayerStatus.Idle);
@@ -352,10 +361,11 @@ describe('State transitions', () => {
player.play(resource);
expect(player.checkPlayable()).toEqual(true);
expect(player.state.status).toEqual(AudioPlayerStatus.Playing);
for (let i = 0; i < 3; i++) {
for (let index = 0; index < 3; index++) {
resource.playStream.read();
await wait();
}
expect(resource.playStream.readableEnded).toEqual(true);
expect(player.checkPlayable()).toEqual(false);
expect(player.state.status).toEqual(AudioPlayerStatus.Idle);
@@ -367,10 +377,11 @@ test('play() throws when playing a resource that has already ended', async () =>
player = createAudioPlayer();
player.play(resource);
expect(player.state.status).toEqual(AudioPlayerStatus.Playing);
for (let i = 0; i < 3; i++) {
for (let index = 0; index < 3; index++) {
resource.playStream.read();
await wait();
}
expect(resource.playStream.readableEnded).toEqual(true);
player.stop(true);
expect(player.state.status).toEqual(AudioPlayerStatus.Idle);

View File

@@ -1,9 +1,11 @@
/* eslint-disable no-promise-executor-return */
import { Buffer } from 'node:buffer';
import { SILENCE_FRAME } from '../src/audio/AudioPlayer';
import { AudioReceiveStream, EndBehaviorType } from '../src/receive/AudioReceiveStream';
const DUMMY_BUFFER = Buffer.allocUnsafe(16);
function wait(ms: number) {
async function wait(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
@@ -52,13 +54,13 @@ describe('AudioReceiveStream', () => {
const stream = new AudioReceiveStream({ end: { behavior: EndBehaviorType.AfterInactivity, duration: 100 } });
stream.resume();
for (let i = increment; i < duration / 2; i += increment) {
for (let index = increment; index < duration / 2; index += increment) {
await stepSilence(stream, increment);
}
stream.push(DUMMY_BUFFER);
for (let i = increment; i < duration; i += increment) {
for (let index = increment; index < duration; index += increment) {
await stepSilence(stream, increment);
}

View File

@@ -1,14 +1,17 @@
/* eslint-disable @typescript-eslint/no-unsafe-return */
import { Buffer } from 'node:buffer';
import process from 'node:process';
import { PassThrough, Readable } from 'node:stream';
import { opus, VolumeTransformer } from 'prism-media';
import { SILENCE_FRAME } from '../src/audio/AudioPlayer';
import { AudioResource, createAudioResource, NO_CONSTRAINT, VOLUME_CONSTRAINT } from '../src/audio/AudioResource';
import { Edge, findPipeline as _findPipeline, StreamType, TransformerType } from '../src/audio/TransformerGraph';
import { findPipeline as _findPipeline, StreamType, TransformerType, type Edge } from '../src/audio/TransformerGraph';
jest.mock('prism-media');
jest.mock('../src/audio/TransformerGraph');
function wait() {
async function wait() {
// eslint-disable-next-line no-promise-executor-return
return new Promise((resolve) => process.nextTick(resolve));
}
@@ -16,12 +19,14 @@ async function started(resource: AudioResource) {
while (!resource.started) {
await wait();
}
return resource;
}
const findPipeline = _findPipeline as unknown as jest.MockedFunction<typeof _findPipeline>;
beforeAll(() => {
// @ts-expect-error no type
findPipeline.mockImplementation((from: StreamType, constraint: (path: Edge[]) => boolean) => {
const base = [
{
@@ -38,6 +43,7 @@ beforeAll(() => {
type: TransformerType.InlineVolume,
});
}
return base as any[];
});
});
@@ -113,11 +119,12 @@ describe('createAudioResource', () => {
await started(resource);
expect(resource.readable).toEqual(true);
expect(resource.read()).toEqual(Buffer.from([1]));
for (let i = 0; i < 5; i++) {
for (let index = 0; index < 5; index++) {
await wait();
expect(resource.readable).toEqual(true);
expect(resource.read()).toEqual(SILENCE_FRAME);
}
await wait();
expect(resource.readable).toEqual(false);
expect(resource.read()).toEqual(null);

View File

@@ -2,8 +2,9 @@
/* eslint-disable @typescript-eslint/dot-notation */
import { GatewayOpcodes } from 'discord-api-types/v10';
import * as DataStore from '../src/DataStore';
import { VoiceConnection } from '../src/VoiceConnection';
import type { VoiceConnection } from '../src/VoiceConnection';
import * as _AudioPlayer from '../src/audio/AudioPlayer';
jest.mock('../src/VoiceConnection');
jest.mock('../src/audio/AudioPlayer');
@@ -15,8 +16,9 @@ function createVoiceConnection(joinConfig: Pick<DataStore.JoinConfig, 'group' |
} as any;
}
function waitForEventLoop() {
return new Promise((res) => setImmediate(res));
async function waitForEventLoop() {
// eslint-disable-next-line no-promise-executor-return
return new Promise((resolve) => setImmediate(resolve));
}
beforeEach(() => {
@@ -24,6 +26,7 @@ beforeEach(() => {
for (const groupKey of groups.keys()) {
groups.delete(groupKey);
}
groups.set('default', new Map());
});
@@ -41,6 +44,7 @@ describe('DataStore', () => {
};
expect(DataStore.createJoinVoiceChannelPayload(joinConfig)).toStrictEqual({
op: GatewayOpcodes.VoiceStateUpdate,
// eslint-disable-next-line id-length
d: {
guild_id: joinConfig.guildId,
channel_id: joinConfig.channelId,
@@ -60,7 +64,7 @@ describe('DataStore', () => {
expect([...DataStore.getVoiceConnections().values()]).toEqual([voiceConnectionDefault]);
expect([...DataStore.getVoiceConnections('default').values()]).toEqual([voiceConnectionDefault]);
expect([...DataStore.getVoiceConnections('abc').values()]).toEqual([voiceConnectionAbc]);
expect([...DataStore.getVoiceConnections('abc')!.values()]).toEqual([voiceConnectionAbc]);
DataStore.untrackVoiceConnection(voiceConnectionDefault);
expect(DataStore.getVoiceConnection('123')).toBeUndefined();
@@ -73,6 +77,7 @@ describe('DataStore', () => {
expect(DataStore.hasAudioPlayer(player)).toEqual(true);
expect(DataStore.addAudioPlayer(player)).toEqual(player);
DataStore.deleteAudioPlayer(player);
// eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
expect(DataStore.deleteAudioPlayer(player)).toBeUndefined();
expect(DataStore.hasAudioPlayer(player)).toEqual(false);
// Tests audio cycle with nextTime === -1

View File

@@ -1,8 +1,10 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import EventEmitter, { once } from 'node:events';
import { SSRCMap, VoiceUserData } from '../src/receive/SSRCMap';
import type EventEmitter from 'node:events';
import { once } from 'node:events';
import process from 'node:process';
import { SSRCMap, type VoiceUserData } from '../src/receive/SSRCMap';
function onceOrThrow<T extends EventEmitter>(target: T, event: string, after: number) {
async function onceOrThrow<T extends EventEmitter>(target: T, event: string, after: number) {
return new Promise((resolve, reject) => {
target.on(event, resolve);
setTimeout(() => reject(new Error('Time up')), after);

View File

@@ -3,6 +3,6 @@ import { methods } from '../src/util/Secretbox';
jest.mock('tweetnacl');
test('Does not throw error with a package installed', () => {
// @ts-expect-error
// @ts-expect-error: Unknown type
expect(() => methods.open()).not.toThrowError();
});

View File

@@ -14,7 +14,7 @@ describe('SpeakingMap', () => {
speaking.on('start', (userId) => void starts.push(userId));
speaking.on('end', (userId) => void ends.push(userId));
for (let i = 0; i < 10; i++) {
for (let index = 0; index < 10; index++) {
speaking.onPacket(userId);
setTimeout(noop, SpeakingMap.DELAY / 2);
jest.advanceTimersToNextTimer();
@@ -22,6 +22,7 @@ describe('SpeakingMap', () => {
expect(starts).toEqual([userId]);
expect(ends).toEqual([]);
}
jest.advanceTimersToNextTimer();
expect(ends).toEqual([userId]);

View File

@@ -1,4 +1,4 @@
import { Edge, findPipeline, StreamType, TransformerType } from '../src/audio/TransformerGraph';
import { findPipeline, StreamType, TransformerType, type Edge } from '../src/audio/TransformerGraph';
const noConstraint = () => true;
@@ -12,6 +12,7 @@ function reducePath(pipeline: Edge[]) {
for (const edge of pipeline.slice(1)) {
streams.push(edge.from.type);
}
streams.push(pipeline[pipeline.length - 1].to.type);
return streams;
}

View File

@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/unbound-method */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
@@ -8,13 +9,12 @@ import * as _DataStore from '../src/DataStore';
import {
createVoiceConnection,
VoiceConnection,
VoiceConnectionConnectingState,
VoiceConnectionDisconnectReason,
VoiceConnectionReadyState,
VoiceConnectionSignallingState,
VoiceConnectionStatus,
type VoiceConnectionConnectingState,
type VoiceConnectionReadyState,
type VoiceConnectionSignallingState,
} from '../src/VoiceConnection';
import * as _AudioPlayer from '../src/audio/AudioPlayer';
import { PlayerSubscription as _PlayerSubscription } from '../src/audio/PlayerSubscription';
import * as _Networking from '../src/networking/Networking';
@@ -129,6 +129,7 @@ describe('createVoiceConnection', () => {
const stateSetter = jest.spyOn(existingVoiceConnection, 'state', 'set');
// @ts-expect-error: We're testing
DataStore.getVoiceConnection.mockImplementation((guildId, group = 'default') =>
guildId === existingJoinConfig.guildId && group === existingJoinConfig.group ? existingVoiceConnection : null,
);
@@ -167,6 +168,7 @@ describe('createVoiceConnection', () => {
const rejoinSpy = jest.spyOn(existingVoiceConnection, 'rejoin');
// @ts-expect-error: We're testing
DataStore.getVoiceConnection.mockImplementation((guildId, group = 'default') =>
guildId === existingJoinConfig.guildId && group === existingJoinConfig.group ? existingVoiceConnection : null,
);
@@ -198,6 +200,7 @@ describe('createVoiceConnection', () => {
adapterCreator: existingAdapter.creator,
});
// @ts-expect-error: We're testing
DataStore.getVoiceConnection.mockImplementation((guildId, group = 'default') =>
guildId === existingJoinConfig.guildId && group === existingJoinConfig.group ? existingVoiceConnection : null,
);
@@ -355,17 +358,17 @@ describe('VoiceConnection#onNetworkingClose', () => {
voiceConnection.state = {
status: VoiceConnectionStatus.Destroyed,
};
voiceConnection['onNetworkingClose'](1000);
voiceConnection['onNetworkingClose'](1_000);
expect(voiceConnection.state.status).toEqual(VoiceConnectionStatus.Destroyed);
expect(adapter.sendPayload).not.toHaveBeenCalled();
});
test('Disconnects for code 4014', () => {
const { voiceConnection, adapter } = createFakeVoiceConnection();
voiceConnection['onNetworkingClose'](4014);
voiceConnection['onNetworkingClose'](4_014);
expect(voiceConnection.state).toMatchObject({
status: VoiceConnectionStatus.Disconnected,
closeCode: 4014,
closeCode: 4_014,
});
expect(adapter.sendPayload).not.toHaveBeenCalled();
});
@@ -376,7 +379,7 @@ describe('VoiceConnection#onNetworkingClose', () => {
DataStore.createJoinVoiceChannelPayload.mockImplementation((config) =>
config === joinConfig ? dummyPayload : undefined,
);
voiceConnection['onNetworkingClose'](1234);
voiceConnection['onNetworkingClose'](1_234);
expect(voiceConnection.state.status).toEqual(VoiceConnectionStatus.Signalling);
expect(adapter.sendPayload).toHaveBeenCalledWith(dummyPayload);
expect(voiceConnection.rejoinAttempts).toEqual(1);
@@ -389,7 +392,7 @@ describe('VoiceConnection#onNetworkingClose', () => {
config === joinConfig ? dummyPayload : undefined,
);
adapter.sendPayload.mockReturnValue(false);
voiceConnection['onNetworkingClose'](1234);
voiceConnection['onNetworkingClose'](1_234);
expect(voiceConnection.state.status).toEqual(VoiceConnectionStatus.Disconnected);
expect(adapter.sendPayload).toHaveBeenCalledWith(dummyPayload);
expect(voiceConnection.rejoinAttempts).toEqual(1);
@@ -552,7 +555,7 @@ describe('VoiceConnection#rejoin', () => {
...(voiceConnection.state as VoiceConnectionSignallingState),
status: VoiceConnectionStatus.Disconnected,
reason: VoiceConnectionDisconnectReason.WebSocketClose,
closeCode: 1000,
closeCode: 1_000,
};
expect(voiceConnection.rejoin()).toEqual(true);
expect(voiceConnection.rejoinAttempts).toEqual(1);
@@ -584,7 +587,7 @@ describe('VoiceConnection#rejoin', () => {
...(voiceConnection.state as VoiceConnectionSignallingState),
status: VoiceConnectionStatus.Disconnected,
reason: VoiceConnectionDisconnectReason.WebSocketClose,
closeCode: 1000,
closeCode: 1_000,
};
adapter.sendPayload.mockReturnValue(false);
expect(voiceConnection.rejoin()).toEqual(false);
@@ -751,7 +754,7 @@ describe('Adapter', () => {
const { adapter, voiceConnection } = createFakeVoiceConnection();
voiceConnection['addServerPacket'] = jest.fn();
const dummy = Symbol('dummy') as any;
adapter.libMethods.onVoiceServerUpdate(dummy);
adapter.libMethods.onVoiceServerUpdate!(dummy);
expect(voiceConnection['addServerPacket']).toHaveBeenCalledWith(dummy);
});
@@ -759,13 +762,13 @@ describe('Adapter', () => {
const { adapter, voiceConnection } = createFakeVoiceConnection();
voiceConnection['addStatePacket'] = jest.fn();
const dummy = Symbol('dummy') as any;
adapter.libMethods.onVoiceStateUpdate(dummy);
adapter.libMethods.onVoiceStateUpdate!(dummy);
expect(voiceConnection['addStatePacket']).toHaveBeenCalledWith(dummy);
});
test('destroy', () => {
const { adapter, voiceConnection } = createFakeVoiceConnection();
adapter.libMethods.destroy();
adapter.libMethods.destroy!();
expect(voiceConnection.state.status).toEqual(VoiceConnectionStatus.Destroyed);
expect(adapter.sendPayload).not.toHaveBeenCalled();
});

View File

@@ -1,6 +1,9 @@
/* eslint-disable id-length */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/dot-notation */
import { Buffer } from 'node:buffer';
import { once } from 'node:events';
import process from 'node:process';
import { VoiceOpcodes } from 'discord-api-types/voice/v4';
import { RTP_PACKET_DESKTOP, RTP_PACKET_CHROME, RTP_PACKET_ANDROID } from '../__mocks__/rtp';
import { VoiceConnection as _VoiceConnection, VoiceConnectionStatus } from '../src/VoiceConnection';
@@ -16,7 +19,8 @@ openSpy.mockImplementation((buffer) => buffer);
const VoiceConnection = _VoiceConnection as unknown as jest.Mocked<typeof _VoiceConnection>;
function nextTick() {
async function nextTick() {
// eslint-disable-next-line no-promise-executor-return
return new Promise((resolve) => process.nextTick(resolve));
}
@@ -178,7 +182,7 @@ describe('VoiceReceiver', () => {
// Assert
expect(nonce.equals(range(29, 32))).toEqual(true);
expect(decrypted.equals(range(13, 28))).toEqual(true);
expect(decrypted!.equals(range(13, 28))).toEqual(true);
});
test('decrypt: xsalsa20_poly1305_suffix', () => {
@@ -191,7 +195,7 @@ describe('VoiceReceiver', () => {
// Assert
expect(nonce.equals(range(41, 64))).toEqual(true);
expect(decrypted.equals(range(13, 40))).toEqual(true);
expect(decrypted!.equals(range(13, 40))).toEqual(true);
});
test('decrypt: xsalsa20_poly1305', () => {
@@ -204,7 +208,7 @@ describe('VoiceReceiver', () => {
// Assert
expect(nonce.equals(range(1, 12))).toEqual(true);
expect(decrypted.equals(range(13, 64))).toEqual(true);
expect(decrypted!.equals(range(13, 64))).toEqual(true);
});
});
});

View File

@@ -1,6 +1,7 @@
/* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/no-empty-function */
/* eslint-disable @typescript-eslint/no-unused-vars */
import { Buffer } from 'node:buffer';
import { createSocket as _createSocket } from 'node:dgram';
import EventEmitter, { once } from 'node:events';
import { VoiceUDPSocket } from '../src/networking/VoiceUDPSocket';
@@ -16,6 +17,7 @@ beforeEach(() => {
class FakeSocket extends EventEmitter {
public send(buffer: Buffer, port: number, address: string) {}
public close() {
this.emit('close');
}
@@ -29,7 +31,7 @@ const VALID_RESPONSE = Buffer.from([
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd3, 0x84,
]);
function wait() {
async function wait() {
return new Promise((resolve) => {
setImmediate(resolve);
jest.advanceTimersToNextTimer();
@@ -52,13 +54,13 @@ describe('VoiceUDPSocket#performIPDiscovery', () => {
fake.emit('message', VALID_RESPONSE);
});
createSocket.mockImplementation((type) => fake as any);
socket = new VoiceUDPSocket({ ip: '1.2.3.4', port: 25565 });
socket = new VoiceUDPSocket({ ip: '1.2.3.4', port: 25_565 });
expect(createSocket).toHaveBeenCalledWith('udp4');
expect(fake.listenerCount('message')).toEqual(1);
await expect(socket.performIPDiscovery(1234)).resolves.toEqual({
await expect(socket.performIPDiscovery(1_234)).resolves.toEqual({
ip: '91.90.123.93',
port: 54148,
port: 54_148,
});
// Ensure clean up occurs
expect(fake.listenerCount('message')).toEqual(1);
@@ -77,13 +79,13 @@ describe('VoiceUDPSocket#performIPDiscovery', () => {
fake.emit('message', VALID_RESPONSE);
});
createSocket.mockImplementation(() => fake as any);
socket = new VoiceUDPSocket({ ip: '1.2.3.4', port: 25565 });
socket = new VoiceUDPSocket({ ip: '1.2.3.4', port: 25_565 });
expect(createSocket).toHaveBeenCalledWith('udp4');
expect(fake.listenerCount('message')).toEqual(1);
await expect(socket.performIPDiscovery(1234)).resolves.toEqual({
await expect(socket.performIPDiscovery(1_234)).resolves.toEqual({
ip: '91.90.123.93',
port: 54148,
port: 54_148,
});
// Ensure clean up occurs
expect(fake.listenerCount('message')).toEqual(1);
@@ -96,10 +98,10 @@ describe('VoiceUDPSocket#performIPDiscovery', () => {
fake.close();
});
createSocket.mockImplementation(() => fake as any);
socket = new VoiceUDPSocket({ ip: '1.2.3.4', port: 25565 });
socket = new VoiceUDPSocket({ ip: '1.2.3.4', port: 25_565 });
expect(createSocket).toHaveBeenCalledWith('udp4');
await expect(socket.performIPDiscovery(1234)).rejects.toThrowError();
await expect(socket.performIPDiscovery(1_234)).rejects.toThrowError();
});
test('Stays alive when messages are echoed back', async () => {
@@ -109,13 +111,12 @@ describe('VoiceUDPSocket#performIPDiscovery', () => {
fake.emit('message', buffer);
});
createSocket.mockImplementation(() => fake as any);
socket = new VoiceUDPSocket({ ip: '1.2.3.4', port: 25565 });
socket = new VoiceUDPSocket({ ip: '1.2.3.4', port: 25_565 });
let closed = false;
// @ts-expect-error
socket.on('close', () => (closed = true));
for (let i = 0; i < 30; i++) {
for (let index = 0; index < 30; index++) {
jest.advanceTimersToNextTimer();
await wait();
}
@@ -127,13 +128,12 @@ describe('VoiceUDPSocket#performIPDiscovery', () => {
const fake = new FakeSocket();
fake.send = jest.fn();
createSocket.mockImplementation(() => fake as any);
socket = new VoiceUDPSocket({ ip: '1.2.3.4', port: 25565 });
socket = new VoiceUDPSocket({ ip: '1.2.3.4', port: 25_565 });
let closed = false;
// @ts-expect-error
socket.on('close', () => (closed = true));
for (let i = 0; i < 15; i++) {
for (let index = 0; index < 15; index++) {
jest.advanceTimersToNextTimer();
await wait();
}
@@ -146,25 +146,27 @@ describe('VoiceUDPSocket#performIPDiscovery', () => {
const fakeSend = jest.fn();
fake.send = fakeSend;
createSocket.mockImplementation(() => fake as any);
socket = new VoiceUDPSocket({ ip: '1.2.3.4', port: 25565 });
socket = new VoiceUDPSocket({ ip: '1.2.3.4', port: 25_565 });
let closed = false;
// @ts-expect-error
socket.on('close', () => (closed = true));
for (let i = 0; i < 10; i++) {
for (let index = 0; index < 10; index++) {
jest.advanceTimersToNextTimer();
await wait();
}
fakeSend.mockImplementation(async (buffer: Buffer) => {
await wait();
fake.emit('message', buffer);
});
expect(closed).toEqual(false);
for (let i = 0; i < 30; i++) {
for (let index = 0; index < 30; index++) {
jest.advanceTimersToNextTimer();
await wait();
}
expect(closed).toEqual(false);
});
});

View File

@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import EventEmitter, { once } from 'node:events';
import { type EventEmitter, once } from 'node:events';
import { VoiceOpcodes } from 'discord-api-types/voice/v4';
import WS from 'jest-websocket-mock';
import { VoiceWebSocket } from '../src/networking/VoiceWebSocket';
@@ -9,13 +9,13 @@ beforeEach(() => {
WS.clean();
});
function onceIgnoreError<T extends EventEmitter>(target: T, event: string) {
async function onceIgnoreError<T extends EventEmitter>(target: T, event: string) {
return new Promise((resolve) => {
target.on(event, resolve);
});
}
function onceOrThrow<T extends EventEmitter>(target: T, event: string, after: number) {
async function onceOrThrow<T extends EventEmitter>(target: T, event: string, after: number) {
return new Promise((resolve, reject) => {
target.on(event, resolve);
setTimeout(() => reject(new Error('Time up')), after);
@@ -46,7 +46,7 @@ describe.skip('VoiceWebSocket: packet parsing', () => {
server.send('asdf');
await expect(rcv).rejects.toThrowError();
const dummy = { op: 1234 };
const dummy = { op: 1_234 };
rcv = once(ws, 'packet');
server.send(JSON.stringify(dummy));
await expect(rcv).resolves.toEqual([dummy]);
@@ -94,17 +94,19 @@ describe.skip('VoiceWebSocket: heartbeating', () => {
await server.connected;
const rcv = onceOrThrow(ws, 'close', 750);
ws.setHeartbeatInterval(50);
for (let i = 0; i < 10; i++) {
for (let index = 0; index < 10; index++) {
const packet: any = await server.nextMessage;
expect(packet).toMatchObject({
op: VoiceOpcodes.Heartbeat,
});
server.send({
op: VoiceOpcodes.HeartbeatAck,
// eslint-disable-next-line id-length
d: packet.d,
});
expect(ws.ping).toBeGreaterThanOrEqual(0);
}
ws.setHeartbeatInterval(-1);
await expect(rcv).rejects.toThrowError();
});

View File

@@ -1,10 +1,12 @@
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import { Buffer } from 'node:buffer';
import EventEmitter, { once } from 'node:events';
import process from 'node:process';
import { Readable } from 'node:stream';
import { opus as _opus } from 'prism-media';
import { StreamType } from '../src/audio';
import { StreamType } from '../src/audio/index';
import { demuxProbe } from '../src/util/demuxProbe';
jest.mock('prism-media');
@@ -12,19 +14,21 @@ jest.mock('prism-media');
const WebmDemuxer = _opus.WebmDemuxer as unknown as jest.Mock<_opus.WebmDemuxer>;
const OggDemuxer = _opus.OggDemuxer as unknown as jest.Mock<_opus.OggDemuxer>;
function nextTick() {
async function nextTick() {
// eslint-disable-next-line no-promise-executor-return
return new Promise((resolve) => process.nextTick(resolve));
}
async function* gen(n: number) {
for (let i = 0; i < n; i++) {
yield Buffer.from([i]);
async function* gen(num: number) {
for (let index = 0; index < num; index++) {
yield Buffer.from([index]);
await nextTick();
}
}
function range(n: number) {
return Buffer.from(Array.from(Array(n).keys()));
function range(num: number) {
// eslint-disable-next-line unicorn/no-new-array
return Buffer.from(Array.from(new Array(num).keys()));
}
const validHead = Buffer.from([
@@ -41,6 +45,7 @@ async function collectStream(stream: Readable): Promise<Buffer> {
for await (const data of stream) {
output = Buffer.concat([output, data]);
}
return output;
}
@@ -107,10 +112,10 @@ describe('demuxProbe', () => {
});
test('Gives up on larger streams', async () => {
const stream = Readable.from(gen(8192), { objectMode: false });
const stream = Readable.from(gen(8_192), { objectMode: false });
const probe = await demuxProbe(stream);
expect(probe.type).toEqual(StreamType.Arbitrary);
await expect(collectStream(probe.stream)).resolves.toEqual(range(8192));
await expect(collectStream(probe.stream)).resolves.toEqual(range(8_192));
});
test('Propagates errors', async () => {

View File

@@ -1,7 +1,8 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import EventEmitter from 'node:events';
import { VoiceConnection, VoiceConnectionStatus } from '../src/VoiceConnection';
import process from 'node:process';
import { VoiceConnectionStatus, type VoiceConnection } from '../src/VoiceConnection';
import { entersState } from '../src/util/entersState';
function createFakeVoiceConnection(status = VoiceConnectionStatus.Signalling) {
@@ -20,13 +21,13 @@ describe('entersState', () => {
const vc = createFakeVoiceConnection();
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
process.nextTick(() => vc.emit(VoiceConnectionStatus.Ready, null as any, null as any));
const result = await entersState(vc, VoiceConnectionStatus.Ready, 1000);
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, 1000);
const promise = entersState(vc, VoiceConnectionStatus.Ready, 1_000);
jest.runAllTimers();
await expect(promise).rejects.toThrowError();
});
@@ -51,6 +52,6 @@ describe('entersState', () => {
test('Resolves immediately when target already in desired state', async () => {
const vc = createFakeVoiceConnection();
await expect(entersState(vc, VoiceConnectionStatus.Signalling, 1000)).resolves.toEqual(vc);
await expect(entersState(vc, VoiceConnectionStatus.Signalling, 1_000)).resolves.toEqual(vc);
});
});