/* eslint-disable max-lines-per-function -- Test suites naturally have many cases */ /* eslint-disable max-nested-callbacks -- Vitest structure requires nesting */ /** * @file Tests for daily challenge progress utilities. * @copyright nhcarrigan * @license Naomi's Public License * @author Naomi Carrigan */ import { describe, expect, it } from "vitest"; import { updateChallengeProgress } from "../src/utils/dailyChallenges.js"; import type { DailyChallengeState } from "@elysium/types"; const makeState = (overrides: Partial = {}): DailyChallengeState => ({ challenges: [], lastResetDay: "2024-01-01", ...overrides, }); describe("updateChallengeProgress", () => { it("should return unchanged state when there are no challenges", () => { const state = makeState(); const { crystalsAwarded, updatedChallenges } = updateChallengeProgress(state, "clicks", 10); expect(crystalsAwarded).toBe(0); expect(updatedChallenges.challenges).toHaveLength(0); }); it("should skip challenges of a different type", () => { const state = makeState({ challenges: [ { completed: false, progress: 0, rewardCrystals: 5, target: 10, type: "gold_earned" }, ], }); const { crystalsAwarded, updatedChallenges } = updateChallengeProgress(state, "clicks", 5); expect(crystalsAwarded).toBe(0); expect(updatedChallenges.challenges[0].progress).toBe(0); }); it("should skip already-completed challenges", () => { const state = makeState({ challenges: [ { completed: true, progress: 10, rewardCrystals: 5, target: 10, type: "clicks" }, ], }); const { crystalsAwarded, updatedChallenges } = updateChallengeProgress(state, "clicks", 5); expect(crystalsAwarded).toBe(0); expect(updatedChallenges.challenges[0].progress).toBe(10); }); it("should increment progress without completing the challenge", () => { const state = makeState({ challenges: [ { completed: false, progress: 0, rewardCrystals: 5, target: 10, type: "clicks" }, ], }); const { crystalsAwarded, updatedChallenges } = updateChallengeProgress(state, "clicks", 4); expect(crystalsAwarded).toBe(0); expect(updatedChallenges.challenges[0].progress).toBe(4); expect(updatedChallenges.challenges[0].completed).toBe(false); }); it("should complete the challenge and award crystals when progress meets target", () => { const state = makeState({ challenges: [ { completed: false, progress: 8, rewardCrystals: 5, target: 10, type: "clicks" }, ], }); const { crystalsAwarded, updatedChallenges } = updateChallengeProgress(state, "clicks", 2); expect(crystalsAwarded).toBe(5); expect(updatedChallenges.challenges[0].completed).toBe(true); expect(updatedChallenges.challenges[0].progress).toBe(10); }); it("should cap progress at the target when amount overshoots", () => { const state = makeState({ challenges: [ { completed: false, progress: 0, rewardCrystals: 3, target: 10, type: "clicks" }, ], }); const { crystalsAwarded, updatedChallenges } = updateChallengeProgress(state, "clicks", 100); expect(crystalsAwarded).toBe(3); expect(updatedChallenges.challenges[0].progress).toBe(10); expect(updatedChallenges.challenges[0].completed).toBe(true); }); it("should accumulate crystals from multiple completed challenges", () => { const state = makeState({ challenges: [ { completed: false, progress: 0, rewardCrystals: 5, target: 10, type: "clicks" }, { completed: false, progress: 0, rewardCrystals: 10, target: 10, type: "clicks" }, ], }); const { crystalsAwarded, updatedChallenges } = updateChallengeProgress(state, "clicks", 10); expect(crystalsAwarded).toBe(15); expect(updatedChallenges.challenges[0].completed).toBe(true); expect(updatedChallenges.challenges[1].completed).toBe(true); }); it("should preserve the lastResetDay from the original state", () => { const state = makeState({ lastResetDay: "2024-06-15" }); const { updatedChallenges } = updateChallengeProgress(state, "clicks", 1); expect(updatedChallenges.lastResetDay).toBe("2024-06-15"); }); });