From 707b627fbe8fc48b7f510723f1464b78b5d9fc21 Mon Sep 17 00:00:00 2001 From: na2na-p Date: Wed, 22 Nov 2023 13:15:17 +0900 Subject: [PATCH] =?UTF-8?q?=E3=83=86=E3=82=B9=E3=83=88=E5=A4=9A=E5=B0=91?= =?UTF-8?q?=E3=83=9E=E3=82=B7=E3=81=AB=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Voice/internal/Voice.class.spec.ts | 117 ++++++++---------- .../internal/Voice/internal/Voice.class.ts | 38 ++---- .../funcs/getActorConnection/index.ts | 1 + .../internal/getActorConnection.func.ts | 35 ++++++ src/features/others/discord/index.ts | 2 +- .../discord/internal/getActorId/index.ts | 1 + .../internal/getActorId.func.ts} | 2 +- .../getInteractionMemberId.func.spec.ts | 23 ++-- .../internal/getInteractionMemberId/index.ts | 1 - 9 files changed, 119 insertions(+), 101 deletions(-) create mode 100644 src/features/core/internal/Voice/internal/funcs/getActorConnection/index.ts create mode 100644 src/features/core/internal/Voice/internal/funcs/getActorConnection/internal/getActorConnection.func.ts create mode 100644 src/features/others/discord/internal/getActorId/index.ts rename src/features/others/discord/internal/{getInteractionMemberId/internal/getInteractionMemberId.func.ts => getActorId/internal/getActorId.func.ts} (91%) rename src/features/others/discord/internal/{getInteractionMemberId => getActorId}/internal/getInteractionMemberId.func.spec.ts (64%) delete mode 100644 src/features/others/discord/internal/getInteractionMemberId/index.ts diff --git a/src/features/core/internal/Voice/internal/Voice.class.spec.ts b/src/features/core/internal/Voice/internal/Voice.class.spec.ts index c75278e2..d006d840 100644 --- a/src/features/core/internal/Voice/internal/Voice.class.spec.ts +++ b/src/features/core/internal/Voice/internal/Voice.class.spec.ts @@ -1,4 +1,4 @@ -import type { Mock } from 'vitest'; +import type { MockedFunction } from 'vitest'; import { joinVoiceChannel, @@ -10,9 +10,10 @@ import type { VoiceConnection, } from '@/features/library/index.js'; import { LogicException } from '@/features/others/Error/LogicException.js'; -import { getInteractionMemberId } from '@/features/others/discord/index.js'; +import { getActorId } from '@/features/others/discord/index.js'; import { Voice } from './Voice.class.js'; +import { getActorConnection } from './funcs/getActorConnection/index.js'; import { JOINABLE_STATE_STATUS, getJoinableStateStatus, @@ -24,7 +25,7 @@ vi.mock('@/features/others/discord/index.js', async () => { )) as object; return { ...actual, - getInteractionMemberId: vi.fn(), + getActorId: vi.fn(), }; }); @@ -49,6 +50,12 @@ vi.mock('./funcs/getJoinableStateStatus/index.js', async () => { }; }); +vi.mock('./funcs/getActorConnection/index.js', () => { + return { + getActorConnection: vi.fn(), + }; +}); + describe('Voice', () => { let voice: Voice; @@ -66,12 +73,12 @@ describe('Voice', () => { reply: vi.fn(), } as unknown as Readonly; - (getInteractionMemberId as Mock).mockResolvedValueOnce({ + (getActorId as MockedFunction).mockResolvedValueOnce({ voice: { channel: null }, - }); - (getJoinableStateStatus as Mock).mockReturnValueOnce( - JOINABLE_STATE_STATUS.NOT_FOUND - ); + } as GuildMember); + ( + getJoinableStateStatus as MockedFunction + ).mockReturnValueOnce(JOINABLE_STATE_STATUS.NOT_FOUND); await voice.join({ interaction: mockedInteraction }); @@ -87,12 +94,12 @@ describe('Voice', () => { reply: vi.fn(), } as unknown as Readonly; - (getInteractionMemberId as Mock).mockResolvedValueOnce({ + (getActorId as MockedFunction).mockResolvedValueOnce({ voice: { channel: { joinable: true } }, - }); - (getJoinableStateStatus as Mock).mockReturnValueOnce( - JOINABLE_STATE_STATUS.NOT_JOINABLE - ); + } as GuildMember); + ( + getJoinableStateStatus as MockedFunction + ).mockReturnValueOnce(JOINABLE_STATE_STATUS.NOT_JOINABLE); await voice.join({ interaction: mockedInteraction }); @@ -110,12 +117,12 @@ describe('Voice', () => { reply: vi.fn(), } as unknown as Readonly; - (getInteractionMemberId as Mock).mockResolvedValueOnce({ + (getActorId as MockedFunction).mockResolvedValueOnce({ voice: { channel: { joinable: true, viewable: false } }, - }); - (getJoinableStateStatus as Mock).mockReturnValueOnce( - JOINABLE_STATE_STATUS.NOT_VIEWABLE - ); + } as GuildMember); + ( + getJoinableStateStatus as MockedFunction + ).mockReturnValueOnce(JOINABLE_STATE_STATUS.NOT_VIEWABLE); await voice.join({ interaction: mockedInteraction }); @@ -133,7 +140,7 @@ describe('Voice', () => { reply: vi.fn(), } as unknown as Readonly; - (getInteractionMemberId as Mock).mockRejectedValueOnce( + (getActorId as MockedFunction).mockRejectedValueOnce( new LogicException( 'Channel is null. Please check getJoinableStateStatus()' ) @@ -149,12 +156,12 @@ describe('Voice', () => { reply: vi.fn(), } as unknown as Readonly; - (getInteractionMemberId as Mock).mockResolvedValueOnce({ + (getActorId as MockedFunction).mockResolvedValueOnce({ voice: { channel: null }, - }); - (getJoinableStateStatus as Mock).mockReturnValueOnce( - JOINABLE_STATE_STATUS.JOINABLE - ); + } as GuildMember); + ( + getJoinableStateStatus as MockedFunction + ).mockReturnValueOnce(JOINABLE_STATE_STATUS.JOINABLE); await expect( voice.join({ interaction: mockedInteraction }) @@ -182,11 +189,15 @@ describe('Voice', () => { reply: vi.fn(), } as const as unknown as Readonly; - (getInteractionMemberId as Mock).mockResolvedValueOnce(mockedGuildMember); - (joinVoiceChannel as Mock).mockReturnValueOnce('connection'); - (getJoinableStateStatus as Mock).mockReturnValueOnce( - JOINABLE_STATE_STATUS.JOINABLE + (getActorId as MockedFunction).mockResolvedValueOnce( + mockedGuildMember as GuildMember ); + ( + joinVoiceChannel as MockedFunction + ).mockReturnValueOnce({} as VoiceConnection); + ( + getJoinableStateStatus as MockedFunction + ).mockReturnValueOnce(JOINABLE_STATE_STATUS.JOINABLE); const result = await voice.join({ interaction: mockedInteraction }); @@ -199,7 +210,7 @@ describe('Voice', () => { adapterCreator: expect.any(Function), }); expect(voice['connection']).toEqual([ - { guildId: 'guildId', connection: 'connection' }, + { guildId: 'guildId', connection: {} }, ]); expect(result).toBe(true); }); @@ -210,11 +221,12 @@ describe('Voice', () => { reply: vi.fn(), } as unknown as Readonly; - (getInteractionMemberId as Mock).mockResolvedValueOnce({ + (getActorId as MockedFunction).mockResolvedValueOnce({ voice: { channel: null }, - }); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (getJoinableStateStatus as Mock).mockReturnValueOnce('unknown' as any); + } as GuildMember); + (getJoinableStateStatus as MockedFunction) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + .mockReturnValueOnce('unknown' as any); await expect(voice.join({ interaction })).rejects.toThrowError( 'Unknown joinable type.' @@ -238,36 +250,15 @@ describe('Voice', () => { guildId: 'guildId', } as unknown as Readonly; - voice['connection'] = [ - { - guildId: 'guildId', - connection: { - destroy: vi.fn(), - } as unknown as VoiceConnection, - }, - ]; - - const result = await voice.leave({ interaction }); - - expect(voice['connection']).toEqual([]); - expect(result).toBe(true); - }); - - it('should destroy the connection and return true if the target connection does not exist but the member has a connection', async () => { - const interaction = { - guildId: 'guildId', - } as unknown as Readonly; - - (getInteractionMemberId as Mock).mockResolvedValueOnce({ - guild: { id: 'guildId' }, - }); - (getVoiceConnection as Mock).mockReturnValueOnce({ + ( + getActorConnection as MockedFunction + ).mockResolvedValueOnce({ destroy: vi.fn(), - }); + } as unknown as VoiceConnection); const result = await voice.leave({ interaction }); - expect(getVoiceConnection).toHaveBeenCalledWith('guildId'); + expect(voice['connection']).toEqual([]); expect(result).toBe(true); }); @@ -276,10 +267,12 @@ describe('Voice', () => { guildId: 'guildId', } as unknown as Readonly; - (getInteractionMemberId as Mock).mockResolvedValueOnce({ + (getActorId as MockedFunction).mockResolvedValueOnce({ guild: { id: 'guildId' }, - }); - (getVoiceConnection as Mock).mockReturnValueOnce(null); + } as GuildMember); + ( + getVoiceConnection as MockedFunction + ).mockReturnValueOnce(undefined); const result = await voice.leave({ interaction }); diff --git a/src/features/core/internal/Voice/internal/Voice.class.ts b/src/features/core/internal/Voice/internal/Voice.class.ts index ed1014d1..2012e107 100644 --- a/src/features/core/internal/Voice/internal/Voice.class.ts +++ b/src/features/core/internal/Voice/internal/Voice.class.ts @@ -2,14 +2,11 @@ import type { VoiceConnection, ChatInputCommandInteraction, } from '@/features/library/index.js'; -import { - getVoiceConnection, - isNil, - joinVoiceChannel, -} from '@/features/library/index.js'; +import { isNil, joinVoiceChannel } from '@/features/library/index.js'; import { LogicException } from '@/features/others/Error/LogicException.js'; -import { getInteractionMemberId } from '@/features/others/discord/index.js'; +import { getActorId } from '@/features/others/discord/index.js'; +import { getActorConnection } from './funcs/getActorConnection/index.js'; import { JOINABLE_STATE_STATUS, getJoinableStateStatus, @@ -28,7 +25,7 @@ export class Voice { }) { const { voice: { channel }, - } = await getInteractionMemberId(interaction); + } = await getActorId(interaction); const joinable = getJoinableStateStatus({ channel, }); @@ -85,27 +82,14 @@ export class Voice { }: { interaction: Readonly; }): Promise { - const guildId = interaction.guildId; - if (isNil(guildId)) return false; - - const targetConnection = this.connection.find( - connection => connection.guildId === guildId - ); + const actorConnection = await getActorConnection({ + interaction, + connections: this.connection, + }); - if (isNil(targetConnection)) { - const member = await getInteractionMemberId(interaction); - const connection = getVoiceConnection(member.guild.id); - if (isNil(connection)) { - return false; - } else { - connection.destroy(); - return true; - } - } else { - targetConnection.connection.destroy(); - this.connection = this.connection.filter( - connection => connection.guildId !== guildId - ); + if (isNil(actorConnection)) return false; + else { + actorConnection.destroy(); return true; } } diff --git a/src/features/core/internal/Voice/internal/funcs/getActorConnection/index.ts b/src/features/core/internal/Voice/internal/funcs/getActorConnection/index.ts new file mode 100644 index 00000000..625bcd97 --- /dev/null +++ b/src/features/core/internal/Voice/internal/funcs/getActorConnection/index.ts @@ -0,0 +1 @@ +export { getActorConnection } from './internal/getActorConnection.func.js'; diff --git a/src/features/core/internal/Voice/internal/funcs/getActorConnection/internal/getActorConnection.func.ts b/src/features/core/internal/Voice/internal/funcs/getActorConnection/internal/getActorConnection.func.ts new file mode 100644 index 00000000..b5769e16 --- /dev/null +++ b/src/features/core/internal/Voice/internal/funcs/getActorConnection/internal/getActorConnection.func.ts @@ -0,0 +1,35 @@ +import { + isNil, + type ChatInputCommandInteraction, + type VoiceConnection, + getVoiceConnection, +} from '@/features/library/index.js'; +import { getActorId } from '@/features/others/discord/index.js'; + +export const getActorConnection = async ({ + interaction, + connections, +}: { + interaction: Readonly; + connections: Array<{ + guildId: string; + connection: VoiceConnection; + }>; +}): Promise => { + const guildId = interaction.guildId; + if (isNil(guildId)) return null; + + const connection = connections.find( + connection => connection.guildId === guildId + ); + + if (isNil(connection)) { + const actor = await getActorId(interaction); + const connection = getVoiceConnection(actor.guild.id); + + if (isNil(connection)) return null; + else return connection; + } else { + return connection.connection; + } +}; diff --git a/src/features/others/discord/index.ts b/src/features/others/discord/index.ts index b60f8ccf..afd9ec1e 100644 --- a/src/features/others/discord/index.ts +++ b/src/features/others/discord/index.ts @@ -1,2 +1,2 @@ export { getGuildFromInteraction } from './internal/getGuildFromInteraction/index.js'; -export { getInteractionMemberId } from './internal/getInteractionMemberId/index.js'; +export { getActorId } from './internal/getActorId/index.js'; diff --git a/src/features/others/discord/internal/getActorId/index.ts b/src/features/others/discord/internal/getActorId/index.ts new file mode 100644 index 00000000..877d2b7a --- /dev/null +++ b/src/features/others/discord/internal/getActorId/index.ts @@ -0,0 +1 @@ +export { getActorId } from './internal/getActorId.func.js'; diff --git a/src/features/others/discord/internal/getInteractionMemberId/internal/getInteractionMemberId.func.ts b/src/features/others/discord/internal/getActorId/internal/getActorId.func.ts similarity index 91% rename from src/features/others/discord/internal/getInteractionMemberId/internal/getInteractionMemberId.func.ts rename to src/features/others/discord/internal/getActorId/internal/getActorId.func.ts index 587ebf56..00748190 100644 --- a/src/features/others/discord/internal/getInteractionMemberId/internal/getInteractionMemberId.func.ts +++ b/src/features/others/discord/internal/getActorId/internal/getActorId.func.ts @@ -5,7 +5,7 @@ import { } from '@/features/library/index.js'; import { getGuildFromInteraction } from '@/features/others/discord/index.js'; -export const getInteractionMemberId = async ( +export const getActorId = async ( interaction: Readonly ): Promise => { const guild = getGuildFromInteraction({ interaction }); diff --git a/src/features/others/discord/internal/getInteractionMemberId/internal/getInteractionMemberId.func.spec.ts b/src/features/others/discord/internal/getActorId/internal/getInteractionMemberId.func.spec.ts similarity index 64% rename from src/features/others/discord/internal/getInteractionMemberId/internal/getInteractionMemberId.func.spec.ts rename to src/features/others/discord/internal/getActorId/internal/getInteractionMemberId.func.spec.ts index 79a0468a..ba103d99 100644 --- a/src/features/others/discord/internal/getInteractionMemberId/internal/getInteractionMemberId.func.spec.ts +++ b/src/features/others/discord/internal/getActorId/internal/getInteractionMemberId.func.spec.ts @@ -1,10 +1,13 @@ -import type { Mock } from 'vitest'; +import type { MockedFunction } from 'vitest'; -import type { ChatInputCommandInteraction } from '@/features/library/index.js'; +import type { + ChatInputCommandInteraction, + Guild, +} from '@/features/library/index.js'; import { isNil } from '@/features/library/index.js'; import { getGuildFromInteraction } from '@/features/others/discord/index.js'; -import { getInteractionMemberId } from './getInteractionMemberId.func.js'; +import { getActorId } from './getActorId.func.js'; vi.mock('@/features/library/index.js', () => { return { @@ -22,17 +25,19 @@ const mockedGuild = { members: { fetch: vi.fn().mockResolvedValue('mocked member'), }, -} as const; +} as unknown as Guild; const fakeInteraction = { member: { user: { id: '123' } }, } as ChatInputCommandInteraction; -describe('getInteractionMemberId', () => { +describe('getActorId', () => { it('should fetch the member ID from the interaction', async () => { - (getGuildFromInteraction as unknown as Mock).mockReturnValue(mockedGuild); + ( + getGuildFromInteraction as MockedFunction + ).mockReturnValue(mockedGuild); - const result = await getInteractionMemberId(fakeInteraction); + const result = await getActorId(fakeInteraction); expect(getGuildFromInteraction).toHaveBeenCalledWith({ interaction: fakeInteraction, @@ -46,9 +51,9 @@ describe('getInteractionMemberId', () => { member: null, } as ChatInputCommandInteraction; - (isNil as unknown as Mock).mockReturnValue(true); + (isNil as unknown as MockedFunction).mockReturnValue(true); - await expect(getInteractionMemberId(fakeInteraction)).rejects.toThrow( + await expect(getActorId(fakeInteraction)).rejects.toThrow( 'Member is null.' ); }); diff --git a/src/features/others/discord/internal/getInteractionMemberId/index.ts b/src/features/others/discord/internal/getInteractionMemberId/index.ts deleted file mode 100644 index 338f3c3e..00000000 --- a/src/features/others/discord/internal/getInteractionMemberId/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { getInteractionMemberId } from './internal/getInteractionMemberId.func.js';