import { describe, test, expect, afterAll, mock } from "bun:test"; import type { WebServerInstance } from "./server"; import { createWebServer } from "./server"; interface MockBotStats { bot: { name: string; avatarUrl: string | null }; guilds: number; ping: number; cachedUsers: number; commandsRegistered: number; uptime: number; lastCommandTimestamp: number | null; } // 1. Mock DrizzleClient (dependency of dashboardService) mock.module("@shared/db/DrizzleClient", () => { const mockBuilder = { where: mock(() => Promise.resolve([{ count: "5", balance: 1000n, level: 5, dailyStreak: 2 }])), then: (onfulfilled: any) => onfulfilled([{ count: "5", balance: 1000n, level: 5, dailyStreak: 2 }]), }; const mockFrom = { from: mock(() => mockBuilder), }; return { DrizzleClient: { select: mock(() => mockFrom), query: { transactions: { findMany: mock(() => Promise.resolve([])) }, moderationCases: { findMany: mock(() => Promise.resolve([])) }, users: { findFirst: mock(() => Promise.resolve({ username: "test" })), findMany: mock(() => Promise.resolve([])), }, } }, }; }); // 2. Mock Bot Stats Provider mock.module("../../bot/lib/clientStats", () => ({ getClientStats: mock((): MockBotStats => ({ bot: { name: "TestBot", avatarUrl: null }, guilds: 5, ping: 42, cachedUsers: 100, commandsRegistered: 10, uptime: 3600, lastCommandTimestamp: Date.now(), })), })); // 3. Mock System Events mock.module("@shared/lib/events", () => ({ systemEvents: { on: mock(() => { }), emit: mock(() => { }), }, EVENTS: { DASHBOARD: { NEW_EVENT: "dashboard:new_event", } } })); describe("WebServer Security & Limits", () => { const port = 3001; let serverInstance: WebServerInstance | null = null; afterAll(async () => { if (serverInstance) { await serverInstance.stop(); } }); test("should reject more than 10 concurrent WebSocket connections", async () => { serverInstance = await createWebServer({ port, hostname: "localhost" }); const wsUrl = `ws://localhost:${port}/ws`; const sockets: WebSocket[] = []; try { // Attempt to open 12 connections (limit is 10) for (let i = 0; i < 12; i++) { const ws = new WebSocket(wsUrl); sockets.push(ws); await new Promise(resolve => setTimeout(resolve, 5)); } // Give connections time to settle await new Promise(resolve => setTimeout(resolve, 800)); const pendingCount = serverInstance.server.pendingWebSockets; expect(pendingCount).toBeLessThanOrEqual(10); } finally { sockets.forEach(s => { if (s.readyState === WebSocket.OPEN || s.readyState === WebSocket.CONNECTING) { s.close(); } }); } }); test("should return 200 for health check", async () => { if (!serverInstance) { serverInstance = await createWebServer({ port, hostname: "localhost" }); } const response = await fetch(`http://localhost:${port}/api/health`); expect(response.status).toBe(200); const data = (await response.json()) as { status: string }; expect(data.status).toBe("ok"); }); });