import { describe, expect, it } from "vitest"; import { BLACKJACK_XP_ENABLED, BLACKJACK_XP_CAP, computeBlackjackStatsDelta, readBlackjackStats, xpForProfit, type BlackjackSessionResult, type BlackjackStats, } from "@/lib/minigames/blackjack/stats"; function result(overrides: Partial = {}): BlackjackSessionResult { return { userId: 1, roundsPlayed: 10, roundsWon: 4, blackjacksHit: 1, finalBankroll: 1250, ...overrides, }; } function current(overrides: Partial = {}): BlackjackStats { return { gamesPlayed: 0, roundsWon: 0, blackjacksHit: 0, bestScore: 0, xpEarned: 0, ...overrides, }; } describe("xpForProfit", () => { it("awards the base XP for a breakeven or losing session", () => { expect(xpForProfit(1000)).toBe(5); expect(xpForProfit(500)).toBe(5); }); it("awards no bracket bonus below a full 25% profit", () => { expect(xpForProfit(1100)).toBe(5); expect(xpForProfit(1249)).toBe(5); }); it("awards 10 XP per full 25% profit bracket", () => { expect(xpForProfit(1250)).toBe(15); expect(xpForProfit(1500)).toBe(25); expect(xpForProfit(1750)).toBe(35); expect(xpForProfit(2000)).toBe(45); }); it("caps the payout at the session cap", () => { expect(BLACKJACK_XP_CAP).toBe(50); expect(xpForProfit(2500)).toBe(BLACKJACK_XP_CAP); expect(xpForProfit(100000)).toBe(BLACKJACK_XP_CAP); }); }); describe("BLACKJACK_XP_ENABLED", () => { it("is disabled by default until the XP system is reworked", () => { expect(BLACKJACK_XP_ENABLED).toBe(false); }); }); describe("computeBlackjackStatsDelta", () => { it("increments gamesPlayed by exactly one", () => { const next = computeBlackjackStatsDelta(current({ gamesPlayed: 7 }), result()); expect(next.gamesPlayed).toBe(8); }); it("accumulates rounds won and blackjacks hit", () => { const next = computeBlackjackStatsDelta( current({ roundsWon: 10, blackjacksHit: 2 }), result({ roundsWon: 4, blackjacksHit: 1 }), ); expect(next.roundsWon).toBe(14); expect(next.blackjacksHit).toBe(3); }); it("keeps bestScore when the final bankroll is lower", () => { const next = computeBlackjackStatsDelta( current({ bestScore: 9000 }), result({ finalBankroll: 1250 }), ); expect(next.bestScore).toBe(9000); }); it("raises bestScore when the final bankroll is higher", () => { const next = computeBlackjackStatsDelta( current({ bestScore: 1000 }), result({ finalBankroll: 2400 }), ); expect(next.bestScore).toBe(2400); }); it("adds the profit XP to the existing xpEarned total", () => { const next = computeBlackjackStatsDelta( current({ xpEarned: 100 }), result({ finalBankroll: 1500 }), ); expect(next.xpEarned).toBe(125); }); it("does not mutate the current stats object", () => { const before = current({ gamesPlayed: 1, xpEarned: 125 }); computeBlackjackStatsDelta(before, result()); expect(before).toEqual(current({ gamesPlayed: 1, xpEarned: 125 })); }); }); describe("readBlackjackStats", () => { it("reads blackjack stats from a profile that also carries sibling games", () => { const profile = { progression: { minigames: { poker: { gamesPlayed: 12, xpEarned: 40 }, blackjack: { gamesPlayed: 3, roundsWon: 5, blackjacksHit: 2, bestScore: 1500, xpEarned: 15 }, }, }, }; expect(readBlackjackStats(profile)).toEqual( current({ gamesPlayed: 3, roundsWon: 5, blackjacksHit: 2, bestScore: 1500, xpEarned: 15 }), ); }); it("returns all zeros when the blackjack group is missing", () => { expect(readBlackjackStats({ progression: { minigames: {} } })).toEqual(current()); }); it("returns all zeros for a nullish profile", () => { expect(readBlackjackStats(undefined)).toEqual(current()); }); });