import { DrizzleClient } from "@/lib/DrizzleClient"; import { userService } from "@/modules/user/user.service"; import { questService } from "@/modules/quest/quest.service"; import { inventoryService } from "@/modules/inventory/inventory.service"; import { economyService } from "@/modules/economy/economy.service"; import { classService } from "@/modules/class/class.service"; import { levelingService } from "@/modules/leveling/leveling.service"; import { quests, items, classes, users, inventory } from "@/db/schema"; import { eq } from "drizzle-orm"; const TEST_ID = "999999999"; const TEST_USERNAME = "verification_bot"; const RANDOM_SUFFIX = Math.floor(Math.random() * 10000); const TEST_CLASS_NAME = `Test Class ${RANDOM_SUFFIX}`; const TEST_QUEST_NAME = `Test Quest ${RANDOM_SUFFIX}`; const TEST_ITEM_NAME = `Test Potion ${RANDOM_SUFFIX}`; const TEST_CLASS_ID = BigInt(10000 + RANDOM_SUFFIX); const TEST_QUEST_ID = 10000 + RANDOM_SUFFIX; const TEST_ITEM_ID = 10000 + RANDOM_SUFFIX; async function verify() { console.log("Starting verification..."); try { // Cleanup previous run if checking same ID try { await userService.deleteUser(TEST_ID); } catch { } // 1. Setup Data (Class, Quest, Item) // Ensure we have a class let [cls] = await DrizzleClient.insert(classes).values({ id: TEST_CLASS_ID, name: TEST_CLASS_NAME, balance: 1000n }).returning(); // Ensure we have a quest let [quest] = await DrizzleClient.insert(quests).values({ id: TEST_QUEST_ID, name: TEST_QUEST_NAME, triggerEvent: "manual", rewards: { xp: 500, balance: 100 } }).returning(); // Ensure we have an item let [item] = await DrizzleClient.insert(items).values({ id: TEST_ITEM_ID, name: TEST_ITEM_NAME, price: 50n, iconUrl: "x", imageUrl: "x" }).returning(); // 2. Create User console.log("Creating user..."); await userService.createUser(TEST_ID, TEST_USERNAME); let user = await userService.getUserById(TEST_ID); if (!user) throw new Error("User create failed"); console.log("User created:", user.username); // 3. Assign Class & Modify Class Balance console.log("Assigning class..."); await classService.assignClass(TEST_ID, cls!.id); console.log("Modifying class balance..."); const clsBalBefore = (await DrizzleClient.query.classes.findFirst({ where: eq(classes.id, cls!.id) }))!.balance ?? 0n; await classService.modifyClassBalance(cls!.id, 50n); const clsBalAfter = (await DrizzleClient.query.classes.findFirst({ where: eq(classes.id, cls!.id) }))!.balance ?? 0n; if (clsBalAfter !== clsBalBefore + 50n) throw new Error(`Class balance mismatch: ${clsBalAfter} vs ${clsBalBefore + 50n}`); console.log("Class balance verified."); // 4. Assign & Complete Quest (Check Logic) console.log("Assigning quest..."); await questService.assignQuest(TEST_ID, quest!.id); console.log("Completing quest..."); // Initial state const initialXp = user.xp ?? 0n; const initialBal = user.balance ?? 0n; const result = await questService.completeQuest(TEST_ID, quest!.id); if (!result.success) throw new Error("Quest completion failed"); // Refresh User user = await userService.getUserById(TEST_ID); if (!user) throw new Error("User lost"); console.log("Quest Rewards:", result.rewards); console.log("User State:", { xp: user.xp, balance: user.balance, level: user.level }); if (user.balance !== initialBal + BigInt(result.rewards.balance)) throw new Error("Balance reward logic failed"); if (user.xp !== initialXp + BigInt(result.rewards.xp)) throw new Error("XP reward logic failed"); // 5. Buy Item (Check Atomic Logic) console.log("Buying item..."); const buyResult = await inventoryService.buyItem(TEST_ID, item!.id, 2n); if (!buyResult.success) throw new Error("Buy item failed"); // Refresh User user = await userService.getUserById(TEST_ID); const expectedBal = initialBal + BigInt(result.rewards.balance) - (item!.price! * 2n); if (user!.balance !== expectedBal) throw new Error(`Buy logic balance mismatch: ${user!.balance} vs ${expectedBal}`); const inv = await inventoryService.getInventory(TEST_ID); const invItem = inv.find(i => i.itemId === item!.id); if (!invItem || invItem.quantity !== 2n) throw new Error("Inventory item mismatch"); console.log("Buy Verification Successful."); // Cleanup await userService.deleteUser(TEST_ID); // Also clean up metadata await DrizzleClient.delete(inventory).where(eq(inventory.itemId, TEST_ITEM_ID)); // Cascade should handle user link, but manually cleaning item/quest/class await DrizzleClient.delete(items).where(eq(items.id, TEST_ITEM_ID)); await DrizzleClient.delete(quests).where(eq(quests.id, TEST_QUEST_ID)); await DrizzleClient.delete(classes).where(eq(classes.id, TEST_CLASS_ID)); console.log("Cleanup done. Verification PASSED."); } catch (e) { console.error("Verification FAILED:", e); // Attempt cleanup try { await userService.deleteUser(TEST_ID); } catch { } try { if (TEST_ITEM_ID) await DrizzleClient.delete(inventory).where(eq(inventory.itemId, TEST_ITEM_ID)); } catch { } try { if (TEST_ITEM_ID) await DrizzleClient.delete(items).where(eq(items.id, TEST_ITEM_ID)); } catch { } try { if (TEST_QUEST_ID) await DrizzleClient.delete(quests).where(eq(quests.id, TEST_QUEST_ID)); } catch { } try { if (TEST_CLASS_ID) await DrizzleClient.delete(classes).where(eq(classes.id, TEST_CLASS_ID)); } catch { } process.exit(1); } } verify();