115 lines
3.2 KiB
TypeScript
115 lines
3.2 KiB
TypeScript
import { describe, it, expect, mock, beforeEach } from "bun:test";
|
|
import { temporaryRoleService } from "@shared/modules/system/temp-role.service";
|
|
import { userTimers } from "@db/schema";
|
|
import { TimerType } from "@shared/lib/constants";
|
|
|
|
const mockDelete = mock();
|
|
const mockWhere = mock();
|
|
const mockFindMany = mock();
|
|
|
|
mockDelete.mockReturnValue({ where: mockWhere });
|
|
|
|
// Mock DrizzleClient
|
|
mock.module("@shared/db/DrizzleClient", () => ({
|
|
DrizzleClient: {
|
|
delete: mockDelete,
|
|
query: {
|
|
userTimers: {
|
|
findMany: mockFindMany
|
|
}
|
|
}
|
|
}
|
|
}));
|
|
|
|
// Mock AuroraClient
|
|
const mockRemoveRole = mock();
|
|
const mockFetchMember = mock();
|
|
const mockFetchGuild = mock();
|
|
|
|
mock.module("@/lib/BotClient", () => ({
|
|
AuroraClient: {
|
|
guilds: {
|
|
fetch: mockFetchGuild
|
|
}
|
|
}
|
|
}));
|
|
|
|
mock.module("@shared/lib/env", () => ({
|
|
env: {
|
|
DISCORD_GUILD_ID: "guild123"
|
|
}
|
|
}));
|
|
|
|
describe("temporaryRoleService", () => {
|
|
beforeEach(() => {
|
|
mockDelete.mockClear();
|
|
mockWhere.mockClear();
|
|
mockFindMany.mockClear();
|
|
mockRemoveRole.mockClear();
|
|
mockFetchMember.mockClear();
|
|
mockFetchGuild.mockClear();
|
|
|
|
mockFetchGuild.mockResolvedValue({
|
|
members: {
|
|
fetch: mockFetchMember
|
|
}
|
|
});
|
|
|
|
mockFetchMember.mockResolvedValue({
|
|
user: { tag: "TestUser#1234" },
|
|
roles: { remove: mockRemoveRole }
|
|
});
|
|
});
|
|
|
|
it("should revoke expired roles and delete timers", async () => {
|
|
// Mock findMany to return an expired role timer
|
|
mockFindMany.mockResolvedValue([
|
|
{
|
|
userId: 123n,
|
|
type: TimerType.ACCESS,
|
|
key: 'role_456',
|
|
expiresAt: new Date(Date.now() - 1000),
|
|
metadata: { roleId: '456' }
|
|
}
|
|
]);
|
|
|
|
const count = await temporaryRoleService.processExpiredRoles();
|
|
|
|
expect(count).toBe(1);
|
|
expect(mockFetchGuild).toHaveBeenCalledWith("guild123");
|
|
expect(mockFetchMember).toHaveBeenCalledWith("123");
|
|
expect(mockRemoveRole).toHaveBeenCalledWith("456");
|
|
expect(mockDelete).toHaveBeenCalledWith(userTimers);
|
|
});
|
|
|
|
it("should still delete the timer even if member is not found", async () => {
|
|
mockFindMany.mockResolvedValue([
|
|
{
|
|
userId: 999n,
|
|
type: TimerType.ACCESS,
|
|
key: 'role_789',
|
|
expiresAt: new Date(Date.now() - 1000),
|
|
metadata: {}
|
|
}
|
|
]);
|
|
|
|
// Mock member fetch failure
|
|
mockFetchMember.mockRejectedValue(new Error("Member not found"));
|
|
|
|
const count = await temporaryRoleService.processExpiredRoles();
|
|
|
|
expect(count).toBe(1);
|
|
expect(mockRemoveRole).not.toHaveBeenCalled();
|
|
expect(mockDelete).toHaveBeenCalledWith(userTimers);
|
|
});
|
|
|
|
it("should return 0 if no expired timers exist", async () => {
|
|
mockFindMany.mockResolvedValue([]);
|
|
|
|
const count = await temporaryRoleService.processExpiredRoles();
|
|
|
|
expect(count).toBe(0);
|
|
expect(mockDelete).not.toHaveBeenCalled();
|
|
});
|
|
});
|