import { describe, it, expect, mock, beforeEach } from "bun:test"; import { questService } from "./quest.service"; import { userQuests } from "@/db/schema"; import { eq, and } from "drizzle-orm"; // Mock dependencies const mockFindFirst = mock(); const mockFindMany = mock(); const mockInsert = mock(); const mockUpdate = mock(); const mockDelete = mock(); const mockValues = mock(); const mockReturning = mock(); const mockSet = mock(); const mockWhere = mock(); const mockOnConflictDoNothing = mock(); // Chain setup mockInsert.mockReturnValue({ values: mockValues }); mockValues.mockReturnValue({ onConflictDoNothing: mockOnConflictDoNothing }); mockOnConflictDoNothing.mockReturnValue({ returning: mockReturning }); mockUpdate.mockReturnValue({ set: mockSet }); mockSet.mockReturnValue({ where: mockWhere }); mockWhere.mockReturnValue({ returning: mockReturning }); // Mock DrizzleClient mock.module("@/lib/DrizzleClient", () => { const createMockTx = () => ({ query: { userQuests: { findFirst: mockFindFirst, findMany: mockFindMany }, }, insert: mockInsert, update: mockUpdate, delete: mockDelete, }); return { DrizzleClient: { ...createMockTx(), transaction: async (cb: any) => cb(createMockTx()), } }; }); // Mock External Services const mockModifyUserBalance = mock(); mock.module("@/modules/economy/economy.service", () => ({ economyService: { modifyUserBalance: mockModifyUserBalance } })); const mockAddXp = mock(); mock.module("@/modules/leveling/leveling.service", () => ({ levelingService: { addXp: mockAddXp } })); describe("questService", () => { beforeEach(() => { mockFindFirst.mockReset(); mockFindMany.mockReset(); mockInsert.mockClear(); mockUpdate.mockClear(); mockValues.mockClear(); mockReturning.mockClear(); mockSet.mockClear(); mockWhere.mockClear(); mockOnConflictDoNothing.mockClear(); mockModifyUserBalance.mockClear(); mockAddXp.mockClear(); }); describe("assignQuest", () => { it("should assign quest", async () => { mockReturning.mockResolvedValue([{ userId: 1n, questId: 101 }]); const result = await questService.assignQuest("1", 101); expect(result).toEqual([{ userId: 1n, questId: 101 }] as any); expect(mockInsert).toHaveBeenCalledWith(userQuests); expect(mockValues).toHaveBeenCalledWith({ userId: 1n, questId: 101, progress: 0 }); }); }); describe("updateProgress", () => { it("should update progress", async () => { mockReturning.mockResolvedValue([{ userId: 1n, questId: 101, progress: 50 }]); const result = await questService.updateProgress("1", 101, 50); expect(result).toEqual([{ userId: 1n, questId: 101, progress: 50 }] as any); expect(mockUpdate).toHaveBeenCalledWith(userQuests); expect(mockSet).toHaveBeenCalledWith({ progress: 50 }); }); }); describe("completeQuest", () => { it("should complete quest and grant rewards", async () => { const mockUserQuest = { userId: 1n, questId: 101, completedAt: null, quest: { rewards: { balance: 100, xp: 50 } } }; mockFindFirst.mockResolvedValue(mockUserQuest); const result = await questService.completeQuest("1", 101); expect(result.success).toBe(true); expect(result.rewards.balance).toBe(100n); expect(result.rewards.xp).toBe(50n); // Check updates expect(mockUpdate).toHaveBeenCalledWith(userQuests); expect(mockSet).toHaveBeenCalledWith({ completedAt: expect.any(Date) }); // Check service calls expect(mockModifyUserBalance).toHaveBeenCalledWith("1", 100n, 'QUEST_REWARD', expect.any(String), null, expect.anything()); expect(mockAddXp).toHaveBeenCalledWith("1", 50n, expect.anything()); }); it("should throw if quest not assigned", async () => { mockFindFirst.mockResolvedValue(null); expect(questService.completeQuest("1", 101)).rejects.toThrow("Quest not assigned"); }); it("should throw if already completed", async () => { mockFindFirst.mockResolvedValue({ completedAt: new Date() }); expect(questService.completeQuest("1", 101)).rejects.toThrow("Quest already completed"); }); }); describe("getUserQuests", () => { it("should return user quests", async () => { const mockData = [{ questId: 1 }, { questId: 2 }]; mockFindMany.mockResolvedValue(mockData); const result = await questService.getUserQuests("1"); expect(result).toEqual(mockData as any); }); }); });