Files
discord-rpg-concept/bot/lib/BotClient.test.ts

112 lines
4.0 KiB
TypeScript

import { describe, expect, test, mock, beforeEach, spyOn } from "bun:test";
import { systemEvents, EVENTS } from "@shared/lib/events";
// Mock Discord.js Client and related classes
mock.module("discord.js", () => ({
Client: class {
constructor() { }
on() { }
once() { }
login() { }
destroy() { }
removeAllListeners() { }
},
Collection: Map,
GatewayIntentBits: { Guilds: 1, MessageContent: 1, GuildMessages: 1, GuildMembers: 1 },
REST: class {
setToken() { return this; }
put() { return Promise.resolve([]); }
},
Routes: {
applicationGuildCommands: () => 'guild_route',
applicationCommands: () => 'global_route'
}
}));
// Mock loaders to avoid filesystem access during client init
mock.module("../lib/loaders/CommandLoader", () => ({
CommandLoader: class {
constructor() { }
loadFromDirectory() { return Promise.resolve({ loaded: 0, skipped: 0, errors: [] }); }
}
}));
mock.module("../lib/loaders/EventLoader", () => ({
EventLoader: class {
constructor() { }
loadFromDirectory() { return Promise.resolve({ loaded: 0, skipped: 0, errors: [] }); }
}
}));
// Mock dashboard service to prevent network/db calls during event handling
mock.module("@shared/modules/economy/lootdrop.service", () => ({
lootdropService: { clearCaches: mock(async () => { }) }
}));
mock.module("@shared/modules/trade/trade.service", () => ({
tradeService: { clearSessions: mock(() => { }) }
}));
mock.module("@/modules/admin/item_wizard", () => ({
clearDraftSessions: mock(() => { })
}));
mock.module("@shared/modules/dashboard/dashboard.service", () => ({
dashboardService: {
recordEvent: mock(() => Promise.resolve())
}
}));
describe("AuroraClient System Events", () => {
let AuroraClient: any;
beforeEach(async () => {
systemEvents.removeAllListeners();
const module = await import("./BotClient");
AuroraClient = module.AuroraClient;
AuroraClient.maintenanceMode = false;
// MUST call explicitly now
await AuroraClient.setupSystemEvents();
});
/**
* Test Case: Maintenance Mode Toggle
* Requirement: Client state should update when event is received
*/
test("should toggle maintenanceMode when MAINTENANCE_MODE event is received", async () => {
systemEvents.emit(EVENTS.ACTIONS.MAINTENANCE_MODE, { enabled: true, reason: "Testing" });
await new Promise(resolve => setTimeout(resolve, 30));
expect(AuroraClient.maintenanceMode).toBe(true);
systemEvents.emit(EVENTS.ACTIONS.MAINTENANCE_MODE, { enabled: false });
await new Promise(resolve => setTimeout(resolve, 30));
expect(AuroraClient.maintenanceMode).toBe(false);
});
/**
* Test Case: Command Reload
* Requirement: loadCommands and deployCommands should be called
*/
test("should reload commands when RELOAD_COMMANDS event is received", async () => {
const loadSpy = spyOn(AuroraClient, "loadCommands").mockImplementation(() => Promise.resolve());
const deploySpy = spyOn(AuroraClient, "deployCommands").mockImplementation(() => Promise.resolve());
systemEvents.emit(EVENTS.ACTIONS.RELOAD_COMMANDS);
await new Promise(resolve => setTimeout(resolve, 50));
expect(loadSpy).toHaveBeenCalled();
expect(deploySpy).toHaveBeenCalled();
});
/**
* Test Case: Cache Clearance
* Requirement: Service clear methods should be triggered
*/
test("should trigger service cache clearance when CLEAR_CACHE is received", async () => {
const { lootdropService } = await import("@shared/modules/economy/lootdrop.service");
const { tradeService } = await import("@shared/modules/trade/trade.service");
systemEvents.emit(EVENTS.ACTIONS.CLEAR_CACHE);
await new Promise(resolve => setTimeout(resolve, 50));
expect(lootdropService.clearCaches).toHaveBeenCalled();
expect(tradeService.clearSessions).toHaveBeenCalled();
});
});