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/dashboard/dashboard.service", () => ({ dashboardService: { recordEvent: mock(() => Promise.resolve()) } })); describe("AuroraClient System Events", () => { let AuroraClient: any; beforeEach(async () => { // Clear mocks and re-import client to ensure fresh listeners if possible // Note: AuroraClient is a singleton, so we mostly reset its state const module = await import("./BotClient"); AuroraClient = module.AuroraClient; AuroraClient.maintenanceMode = false; }); /** * 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" }); // Give event loop time to process await new Promise(resolve => setTimeout(resolve, 20)); expect(AuroraClient.maintenanceMode).toBe(true); systemEvents.emit(EVENTS.ACTIONS.MAINTENANCE_MODE, { enabled: false }); await new Promise(resolve => setTimeout(resolve, 20)); 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 () => { // Spy on the methods that should be called const loadSpy = spyOn(AuroraClient, "loadCommands").mockImplementation(() => Promise.resolve()); const deploySpy = spyOn(AuroraClient, "deployCommands").mockImplementation(() => Promise.resolve()); systemEvents.emit(EVENTS.ACTIONS.RELOAD_COMMANDS); // Wait for async handlers await new Promise(resolve => setTimeout(resolve, 50)); expect(loadSpy).toHaveBeenCalled(); expect(deploySpy).toHaveBeenCalled(); }); });