import { describe, it, expect, beforeEach, vi } from "vitest"; import { updateProbabilitiesAfterResult, } from "../probability-updater"; import * as participantResultModel from "~/models/participant-result"; import * as participantEVModel from "~/models/participant-expected-value"; // Mock the dependencies vi.mock("~/models/participant-result"); vi.mock("~/models/participant-expected-value"); vi.mock("~/database/context", () => ({ database: () => ({ query: { participantExpectedValues: { findMany: vi.fn(), }, }, }), })); describe("probability-updater", () => { beforeEach(() => { vi.clearAllMocks(); }); describe("updateProbabilitiesAfterResult", () => { it("should set 100% probability for finished participants at their placement", async () => { // Mock data: One participant finished 1st vi.mocked(participantResultModel.findParticipantResultsBySportsSeasonId).mockResolvedValue([ { id: "result-1", participantId: "participant-1", sportsSeasonId: "season-1", finalPosition: 1, isPartialScore: false, qualifyingPoints: null, notes: null, createdAt: new Date(), updatedAt: new Date(), }, ]); vi.mocked(participantEVModel.getAllParticipantEVsForSeason).mockResolvedValue([ { id: "ev-1", participantId: "participant-1", sportsSeasonId: "season-1", probFirst: "0.1500", probSecond: "0.1300", probThird: "0.1200", probFourth: "0.1100", probFifth: "0.1000", probSixth: "0.0900", probSeventh: "0.0800", probEighth: "0.0700", expectedValue: "50.00", source: "futures_odds", sourceOdds: null, calculatedAt: new Date(), updatedAt: new Date(), }, ]); const upsertSpy = vi.mocked(participantEVModel.upsertParticipantEV).mockResolvedValue({ id: "ev-1", participantId: "participant-1", sportsSeasonId: "season-1", probFirst: "1.0000", probSecond: "0.0000", probThird: "0.0000", probFourth: "0.0000", probFifth: "0.0000", probSixth: "0.0000", probSeventh: "0.0000", probEighth: "0.0000", expectedValue: "100.00", source: "manual", sourceOdds: null, calculatedAt: new Date(), updatedAt: new Date(), }); const result = await updateProbabilitiesAfterResult("season-1", false); expect(result.finishedParticipants).toBe(1); expect(result.updated).toBe(1); expect(result.errors).toHaveLength(0); // Verify upsert was called with correct probabilities expect(upsertSpy).toHaveBeenCalled(); const callArgs = upsertSpy.mock.calls[0][0]; expect(callArgs.participantId).toBe("participant-1"); expect(callArgs.sportsSeasonId).toBe("season-1"); expect(callArgs.probabilities.probFirst).toBe(1); expect(callArgs.probabilities.probSecond).toBe(0); expect(callArgs.source).toBe("manual"); }); it("should handle multiple finished participants", async () => { vi.mocked(participantResultModel.findParticipantResultsBySportsSeasonId).mockResolvedValue([ { id: "result-1", participantId: "participant-1", sportsSeasonId: "season-1", finalPosition: 1, isPartialScore: false, qualifyingPoints: null, notes: null, createdAt: new Date(), updatedAt: new Date(), }, { id: "result-2", participantId: "participant-2", sportsSeasonId: "season-1", finalPosition: 2, isPartialScore: false, qualifyingPoints: null, notes: null, createdAt: new Date(), updatedAt: new Date(), }, ]); vi.mocked(participantEVModel.getAllParticipantEVsForSeason).mockResolvedValue([ { id: "ev-1", participantId: "participant-1", sportsSeasonId: "season-1", probFirst: "0.2000", probSecond: "0.1500", probThird: "0.1000", probFourth: "0.0800", probFifth: "0.0700", probSixth: "0.0600", probSeventh: "0.0500", probEighth: "0.0400", expectedValue: "60.00", source: "futures_odds", sourceOdds: null, calculatedAt: new Date(), updatedAt: new Date(), }, { id: "ev-2", participantId: "participant-2", sportsSeasonId: "season-1", probFirst: "0.1500", probSecond: "0.1500", probThird: "0.1200", probFourth: "0.1000", probFifth: "0.0900", probSixth: "0.0800", probSeventh: "0.0700", probEighth: "0.0600", expectedValue: "55.00", source: "futures_odds", sourceOdds: null, calculatedAt: new Date(), updatedAt: new Date(), }, ]); const upsertSpy = vi.mocked(participantEVModel.upsertParticipantEV).mockResolvedValue({} as any); const result = await updateProbabilitiesAfterResult("season-1", false); expect(result.finishedParticipants).toBe(2); expect(result.updated).toBe(2); expect(result.errors).toHaveLength(0); expect(upsertSpy).toHaveBeenCalledTimes(2); }); it("should handle empty results", async () => { vi.mocked(participantResultModel.findParticipantResultsBySportsSeasonId).mockResolvedValue([]); vi.mocked(participantEVModel.getAllParticipantEVsForSeason).mockResolvedValue([]); const result = await updateProbabilitiesAfterResult("season-1"); expect(result.finishedParticipants).toBe(0); expect(result.unfishedParticipants).toBe(0); expect(result.updated).toBe(0); expect(result.errors).toHaveLength(0); }); it("should handle results without final position", async () => { vi.mocked(participantResultModel.findParticipantResultsBySportsSeasonId).mockResolvedValue([ { id: "result-1", participantId: "participant-1", sportsSeasonId: "season-1", finalPosition: null, // No position set yet isPartialScore: false, qualifyingPoints: "50.00", notes: null, createdAt: new Date(), updatedAt: new Date(), }, ]); vi.mocked(participantEVModel.getAllParticipantEVsForSeason).mockResolvedValue([]); const result = await updateProbabilitiesAfterResult("season-1"); expect(result.finishedParticipants).toBe(0); expect(result.updated).toBe(0); }); it("should set all probabilities to 0% for eliminated participants (finalPosition = 0)", async () => { // Mock: Participant eliminated (didn't make playoffs) vi.mocked(participantResultModel.findParticipantResultsBySportsSeasonId).mockResolvedValue([ { id: "result-1", participantId: "participant-1", sportsSeasonId: "season-1", finalPosition: 0, // Eliminated isPartialScore: false, qualifyingPoints: null, notes: null, createdAt: new Date(), updatedAt: new Date(), }, ]); vi.mocked(participantEVModel.getAllParticipantEVsForSeason).mockResolvedValue([ { id: "ev-1", participantId: "participant-1", sportsSeasonId: "season-1", probFirst: "0.0500", probSecond: "0.0800", probThird: "0.1200", probFourth: "0.1500", probFifth: "0.1600", probSixth: "0.1500", probSeventh: "0.1400", probEighth: "0.1500", expectedValue: "20.00", source: "futures_odds", sourceOdds: null, calculatedAt: new Date(), updatedAt: new Date(), }, ]); const upsertSpy = vi.mocked(participantEVModel.upsertParticipantEV).mockResolvedValue({} as any); const result = await updateProbabilitiesAfterResult("season-1", false); expect(result.finishedParticipants).toBe(1); expect(result.updated).toBe(1); // Verify all probabilities set to 0 const callArgs = upsertSpy.mock.calls[0][0]; expect(callArgs.probabilities.probFirst).toBe(0); expect(callArgs.probabilities.probSecond).toBe(0); expect(callArgs.probabilities.probThird).toBe(0); expect(callArgs.probabilities.probFourth).toBe(0); expect(callArgs.probabilities.probFifth).toBe(0); expect(callArgs.probabilities.probSixth).toBe(0); expect(callArgs.probabilities.probSeventh).toBe(0); expect(callArgs.probabilities.probEighth).toBe(0); }); }); });