
























@@ -5,6 +5,7 @@ import { createVoiceReceiveRecoveryState } from "./receive-recovery.js";
5566const {
77 createConnectionMock,
8+ getVoiceConnectionMock,
89 joinVoiceChannelMock,
910 entersStateMock,
1011 createAudioPlayerMock,
@@ -83,8 +84,11 @@ const {
8384return connection;
8485};
858687+const getVoiceConnectionMock = vi.fn((): MockConnection | undefined => undefined);
88+8689return {
8790 createConnectionMock,
91+ getVoiceConnectionMock,
8892joinVoiceChannelMock: vi.fn(() => createConnectionMock()),
8993entersStateMock: vi.fn(async (_target?: unknown, _state?: string, _timeoutMs?: number) => {
9094return undefined;
@@ -118,6 +122,7 @@ vi.mock("./sdk-runtime.js", () => ({
118122createAudioPlayer: createAudioPlayerMock,
119123createAudioResource: vi.fn(),
120124entersState: entersStateMock,
125+getVoiceConnection: getVoiceConnectionMock,
121126joinVoiceChannel: joinVoiceChannelMock,
122127}),
123128}));
@@ -189,6 +194,8 @@ describe("DiscordVoiceManager", () => {
189194});
190195191196beforeEach(() => {
197+getVoiceConnectionMock.mockReset();
198+getVoiceConnectionMock.mockReturnValue(undefined);
192199joinVoiceChannelMock.mockReset();
193200joinVoiceChannelMock.mockImplementation(() => createConnectionMock());
194201entersStateMock.mockReset();
@@ -313,6 +320,52 @@ describe("DiscordVoiceManager", () => {
313320expectConnectedStatus(manager, "1002");
314321});
315322323+it("destroys stale tracked voice connections before joining", async () => {
324+const staleConnection = createConnectionMock();
325+const connection = createConnectionMock();
326+getVoiceConnectionMock.mockReturnValueOnce(staleConnection);
327+joinVoiceChannelMock.mockReturnValueOnce(connection);
328+const manager = createManager();
329+330+await manager.join({ guildId: "g1", channelId: "1001" });
331+332+expect(getVoiceConnectionMock).toHaveBeenCalledWith("g1");
333+expect(staleConnection.destroy).toHaveBeenCalledTimes(1);
334+expectConnectedStatus(manager, "1001");
335+});
336+337+it("does not throw when stale tracked voice connections are already destroyed", async () => {
338+const staleConnection = createConnectionMock();
339+staleConnection.state.status = "destroyed";
340+staleConnection.destroy.mockImplementation(() => {
341+throw new Error("Cannot destroy VoiceConnection - it has already been destroyed");
342+});
343+getVoiceConnectionMock.mockReturnValueOnce(staleConnection);
344+joinVoiceChannelMock.mockReturnValueOnce(createConnectionMock());
345+const manager = createManager();
346+347+await expect(manager.join({ guildId: "g1", channelId: "1001" })).resolves.toMatchObject({
348+ok: true,
349+});
350+351+expect(staleConnection.destroy).not.toHaveBeenCalled();
352+});
353+354+it("does not throw when leaving an already destroyed voice connection", async () => {
355+const connection = createConnectionMock();
356+connection.destroy.mockImplementation(() => {
357+throw new Error("Cannot destroy VoiceConnection - it has already been destroyed");
358+});
359+joinVoiceChannelMock.mockReturnValueOnce(connection);
360+const manager = createManager();
361+362+await manager.join({ guildId: "g1", channelId: "1001" });
363+connection.state.status = "destroyed";
364+365+await expect(manager.leave({ guildId: "g1" })).resolves.toMatchObject({ ok: true });
366+expect(connection.destroy).not.toHaveBeenCalled();
367+});
368+316369it("removes voice listeners on leave", async () => {
317370const connection = createConnectionMock();
318371joinVoiceChannelMock.mockReturnValueOnce(connection);
@@ -850,4 +903,15 @@ describe("DiscordVoiceManager", () => {
850903await expect(listener.handle(undefined, undefined as never)).resolves.not.toThrow();
851904expect(autoJoinSpy).toHaveBeenCalledTimes(1);
852905});
906+907+it("DiscordVoiceResumedListener: runs autoJoin on gateway resume", async () => {
908+const manager = createManager();
909+const autoJoinSpy = vi.spyOn(manager, "autoJoin").mockResolvedValue(undefined);
910+911+const { DiscordVoiceResumedListener } = managerModule;
912+const listener = new DiscordVoiceResumedListener(manager);
913+914+await expect(listener.handle(undefined, undefined as never)).resolves.not.toThrow();
915+expect(autoJoinSpy).toHaveBeenCalledTimes(1);
916+});
853917});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。