import { describe, it, expect } from "vitest"; import { calculateFantasyPoints, calculateAveragedPoints, type ScoringRules } from "../scoring-rules"; const DEFAULT_SCORING: ScoringRules = { pointsFor1st: 100, pointsFor2nd: 70, pointsFor3rd: 50, pointsFor4th: 40, pointsFor5th: 25, pointsFor6th: 25, pointsFor7th: 15, pointsFor8th: 15, }; describe("Season Standings (F1 Pattern)", () => { describe("Basic Placement Scoring", () => { it("should calculate points for 1st place finisher", () => { const points = calculateFantasyPoints(1, DEFAULT_SCORING); expect(points).toBe(100); }); it("should calculate points for 8th place finisher", () => { const points = calculateFantasyPoints(8, DEFAULT_SCORING); expect(points).toBe(15); }); it("should return 0 points for finishers beyond 8th place", () => { const points = calculateFantasyPoints(0, DEFAULT_SCORING); expect(points).toBe(0); }); }); describe("Tie Scenarios", () => { it("should handle 2-way tie for 3rd place", () => { // Two drivers tied for 3rd get average of 3rd and 4th place points const points = calculateAveragedPoints([3, 4], DEFAULT_SCORING); // (50 + 40) / 2 = 45 expect(points).toBe(45); }); it("should handle 3-way tie for 5th place", () => { // Three drivers tied for 5th share 5th, 6th, and 7th place points const points = calculateAveragedPoints([5, 6, 7], DEFAULT_SCORING); // (25 + 25 + 15) / 3 = 21.67 expect(points).toBeCloseTo(21.67, 2); }); it("should handle 4-way tie for 1st place", () => { // Four drivers tied for 1st (unlikely but possible) const points = calculateAveragedPoints([1, 2, 3, 4], DEFAULT_SCORING); // (100 + 70 + 50 + 40) / 4 = 65 expect(points).toBe(65); }); }); describe("Season Standings Simulation", () => { it("should correctly score a complete F1-style season (no ties)", () => { // Simulate final standings positions 1-10 const standings = [ { driver: "Max Verstappen", position: 1, fantasyPoints: 100 }, { driver: "Lewis Hamilton", position: 2, fantasyPoints: 70 }, { driver: "Charles Leclerc", position: 3, fantasyPoints: 50 }, { driver: "Lando Norris", position: 4, fantasyPoints: 40 }, { driver: "Carlos Sainz", position: 5, fantasyPoints: 25 }, { driver: "George Russell", position: 6, fantasyPoints: 25 }, { driver: "Sergio Perez", position: 7, fantasyPoints: 15 }, { driver: "Fernando Alonso", position: 8, fantasyPoints: 15 }, { driver: "Oscar Piastri", position: 9, fantasyPoints: 0 }, // Beyond top 8 { driver: "Pierre Gasly", position: 10, fantasyPoints: 0 }, // Beyond top 8 ]; standings.forEach((entry) => { const points = calculateFantasyPoints(entry.position, DEFAULT_SCORING); expect(points).toBe(entry.fantasyPoints); }); // Total points if one team drafted all top 8 const totalTop8 = 100 + 70 + 50 + 40 + 25 + 25 + 15 + 15; expect(totalTop8).toBe(340); }); it("should correctly score season with tied positions", () => { // Simulate standings where 3rd, 4th, and 5th are tied const _standings = [ { position: 1, expected: 100 }, { position: 2, expected: 70 }, // Three tied for 3rd place - each gets placement 3 // When scoring, these will share 3rd, 4th, 5th { position: 3, base: 50 }, // Will be averaged: (50+40+25)/3 { position: 3, base: 50 }, { position: 3, base: 50 }, { position: 6, expected: 25 }, { position: 7, expected: 15 }, { position: 8, expected: 15 }, ]; // Verify first two positions expect(calculateFantasyPoints(1, DEFAULT_SCORING)).toBe(100); expect(calculateFantasyPoints(2, DEFAULT_SCORING)).toBe(70); // Verify tied positions get averaged const tiedPoints = calculateAveragedPoints([3, 4, 5], DEFAULT_SCORING); expect(tiedPoints).toBeCloseTo(38.33, 2); // (50 + 40 + 25) / 3 // Verify remaining positions expect(calculateFantasyPoints(6, DEFAULT_SCORING)).toBe(25); expect(calculateFantasyPoints(7, DEFAULT_SCORING)).toBe(15); expect(calculateFantasyPoints(8, DEFAULT_SCORING)).toBe(15); }); it("should handle ties that cross the 8th place boundary", () => { // Simulate where 7th, 8th, and 9th are tied // In practice, 7th and 8th would score, 9th would get 0 // First 7 and 8 get points expect(calculateFantasyPoints(7, DEFAULT_SCORING)).toBe(15); expect(calculateFantasyPoints(8, DEFAULT_SCORING)).toBe(15); // If they share 7th and 8th place const shared7and8 = calculateAveragedPoints([7, 8], DEFAULT_SCORING); expect(shared7and8).toBe(15); // (15 + 15) / 2 = 15 // 9th gets 0 expect(calculateFantasyPoints(0, DEFAULT_SCORING)).toBe(0); }); }); describe("Custom Scoring Rules", () => { it("should work with custom F1 league scoring rules", () => { const customScoring: ScoringRules = { pointsFor1st: 150, pointsFor2nd: 100, pointsFor3rd: 75, pointsFor4th: 60, pointsFor5th: 50, pointsFor6th: 40, pointsFor7th: 30, pointsFor8th: 20, }; expect(calculateFantasyPoints(1, customScoring)).toBe(150); expect(calculateFantasyPoints(8, customScoring)).toBe(20); // Tied positions const tied3rd = calculateAveragedPoints([3, 4], customScoring); expect(tied3rd).toBe(67.5); // (75 + 60) / 2 }); }); describe("Edge Cases", () => { it("should handle all 8 positions tied", () => { // Extremely unlikely but mathematically possible const allTied = calculateAveragedPoints([1, 2, 3, 4, 5, 6, 7, 8], DEFAULT_SCORING); // (100 + 70 + 50 + 40 + 25 + 25 + 15 + 15) / 8 = 42.5 expect(allTied).toBe(42.5); }); it("should handle only top 4 finishing (others DNF/DQ)", () => { // If only 4 participants finish the season expect(calculateFantasyPoints(1, DEFAULT_SCORING)).toBe(100); expect(calculateFantasyPoints(2, DEFAULT_SCORING)).toBe(70); expect(calculateFantasyPoints(3, DEFAULT_SCORING)).toBe(50); expect(calculateFantasyPoints(4, DEFAULT_SCORING)).toBe(40); // Positions 5-8 would have no participants // Any non-finishers get 0 expect(calculateFantasyPoints(0, DEFAULT_SCORING)).toBe(0); }); it("should handle single participant season", () => { // Only 1 participant completes the season const points = calculateFantasyPoints(1, DEFAULT_SCORING); expect(points).toBe(100); }); }); });