refactor: convert ModerationService and PruneService from classes to singleton objects

- Convert ModerationService class to moderationService singleton
- Convert PruneService class to pruneService singleton
- Update all command files to use new singleton imports
- Update web routes to use new singleton imports
- Update tests for singleton pattern
- Remove getNextCaseId from tests (now private module function)
This commit is contained in:
syntaxbullet
2026-02-13 13:33:58 +01:00
parent 55d2376ca1
commit 099601ce6d
13 changed files with 176 additions and 184 deletions

View File

@@ -1,6 +1,6 @@
import { describe, it, expect, mock, beforeEach } from "bun:test";
import { ModerationService } from "@shared/modules/moderation/moderation.service";
import { moderationService } from "@shared/modules/moderation/moderation.service";
import { moderationCases } from "@db/schema";
import { CaseType } from "@shared/lib/constants";
@@ -43,7 +43,7 @@ mockUpdate.mockReturnValue({ set: mockSet });
mockSet.mockReturnValue({ where: mockWhere });
mockWhere.mockReturnValue({ returning: mockReturning });
describe("ModerationService", () => {
describe("moderationService", () => {
beforeEach(() => {
mockFindFirst.mockReset();
mockFindMany.mockReset();
@@ -73,7 +73,7 @@ describe("ModerationService", () => {
const mockDmTarget = { send: mock() };
const result = await ModerationService.issueWarning({
const result = await moderationService.issueWarning({
...defaultOptions,
dmTarget: mockDmTarget
});
@@ -91,7 +91,7 @@ describe("ModerationService", () => {
const mockDmTarget = { send: mock() };
await ModerationService.issueWarning({
await moderationService.issueWarning({
...defaultOptions,
dmTarget: mockDmTarget,
config: { dmOnWarn: false }
@@ -108,7 +108,7 @@ describe("ModerationService", () => {
const mockTimeoutTarget = { timeout: mock() };
const result = await ModerationService.issueWarning({
const result = await moderationService.issueWarning({
...defaultOptions,
timeoutTarget: mockTimeoutTarget,
config: { autoTimeoutThreshold: 3 }
@@ -128,7 +128,7 @@ describe("ModerationService", () => {
const mockTimeoutTarget = { timeout: mock() };
const result = await ModerationService.issueWarning({
const result = await moderationService.issueWarning({
...defaultOptions,
timeoutTarget: mockTimeoutTarget
});
@@ -139,27 +139,6 @@ describe("ModerationService", () => {
});
});
describe("getNextCaseId", () => {
it("should return CASE-0001 if no cases exist", async () => {
mockFindFirst.mockResolvedValue(undefined);
// Accessing private method via bracket notation for testing
const nextId = await (ModerationService as any).getNextCaseId();
expect(nextId).toBe("CASE-0001");
});
it("should increment the latest case ID", async () => {
mockFindFirst.mockResolvedValue({ caseId: "CASE-0042" });
const nextId = await (ModerationService as any).getNextCaseId();
expect(nextId).toBe("CASE-0043");
});
it("should handle padding correctly (e.g., 9 -> 0010)", async () => {
mockFindFirst.mockResolvedValue({ caseId: "CASE-0009" });
const nextId = await (ModerationService as any).getNextCaseId();
expect(nextId).toBe("CASE-0010");
});
});
describe("createCase", () => {
it("should create a new moderation case with correct values", async () => {
mockFindFirst.mockResolvedValue({ caseId: "CASE-0001" });
@@ -176,7 +155,7 @@ describe("ModerationService", () => {
};
mockReturning.mockResolvedValue([mockNewCase]);
const result = await ModerationService.createCase({
const result = await moderationService.createCase({
type: CaseType.WARN,
userId: "123456789",
username: "testuser",
@@ -199,7 +178,7 @@ describe("ModerationService", () => {
mockFindFirst.mockResolvedValue(undefined);
mockReturning.mockImplementation((values) => [values]); // Simplified mock
const result = await ModerationService.createCase({
const result = await moderationService.createCase({
type: CaseType.BAN,
userId: "123456789",
username: "testuser",
@@ -219,7 +198,7 @@ describe("ModerationService", () => {
const mockCase = { caseId: "CASE-0001", reason: "test" };
mockFindFirst.mockResolvedValue(mockCase);
const result = await ModerationService.getCaseById("CASE-0001");
const result = await moderationService.getCaseById("CASE-0001");
expect(result).toEqual(mockCase as any);
});
});
@@ -229,7 +208,7 @@ describe("ModerationService", () => {
const mockCases = [{ caseId: "CASE-0001" }, { caseId: "CASE-0002" }];
mockFindMany.mockResolvedValue(mockCases);
const result = await ModerationService.getUserCases("123456789");
const result = await moderationService.getUserCases("123456789");
expect(result).toHaveLength(2);
expect(mockFindMany).toHaveBeenCalled();
});
@@ -240,7 +219,7 @@ describe("ModerationService", () => {
const mockUpdatedCase = { caseId: "CASE-0001", active: false };
mockReturning.mockResolvedValue([mockUpdatedCase]);
const result = await ModerationService.clearCase({
const result = await moderationService.clearCase({
caseId: "CASE-0001",
clearedBy: "987654321",
clearedByName: "mod",
@@ -264,13 +243,13 @@ describe("ModerationService", () => {
{ id: 2n, type: CaseType.WARN, active: true }
]);
const count = await ModerationService.getActiveWarningCount("123456789");
const count = await moderationService.getActiveWarningCount("123456789");
expect(count).toBe(2);
});
it("should return 0 if no active warnings", async () => {
mockFindMany.mockResolvedValue([]);
const count = await ModerationService.getActiveWarningCount("123456789");
const count = await moderationService.getActiveWarningCount("123456789");
expect(count).toBe(0);
});
});