import { describe, it, expect } from "vitest"; import { normalizeTeamName, getTeamData, eloWinProbability, } from "../nhl-simulator"; // ─── normalizeTeamName ──────────────────────────────────────────────────────── describe("normalizeTeamName", () => { it("lowercases and trims", () => { expect(normalizeTeamName(" Colorado Avalanche ")).toBe("colorado avalanche"); }); it("collapses internal whitespace", () => { expect(normalizeTeamName("Tampa Bay Lightning")).toBe("tampa bay lightning"); }); it("is already-normalized identity", () => { expect(normalizeTeamName("dallas stars")).toBe("dallas stars"); }); }); // ─── getTeamData ────────────────────────────────────────────────────────────── describe("getTeamData", () => { it("returns data for an exact match", () => { const d = getTeamData("Colorado Avalanche"); expect(d).toBeDefined(); expect(d?.conference).toBe("Western"); expect(d?.division).toBe("Central"); expect(d?.elo).toBeGreaterThan(1500); }); it("is case-insensitive", () => { expect(getTeamData("colorado avalanche")).toEqual(getTeamData("Colorado Avalanche")); }); it("returns undefined for an unknown team", () => { expect(getTeamData("Springfield Ice Hounds")).toBeUndefined(); }); it("all 32 teams are present", () => { const allTeams = [ // Eastern — Atlantic "Tampa Bay Lightning", "Buffalo Sabres", "Montreal Canadiens", "Ottawa Senators", "Detroit Red Wings", "Boston Bruins", "Florida Panthers", "Toronto Maple Leafs", // Eastern — Metropolitan "Carolina Hurricanes", "Columbus Blue Jackets", "Pittsburgh Penguins", "New York Islanders", "Philadelphia Flyers", "Washington Capitals", "New Jersey Devils", "New York Rangers", // Western — Central "Colorado Avalanche", "Dallas Stars", "Minnesota Wild", "Utah Mammoth", "Nashville Predators", "Winnipeg Jets", "St. Louis Blues", "Chicago Blackhawks", // Western — Pacific "Anaheim Ducks", "Edmonton Oilers", "Vegas Golden Knights", "Los Angeles Kings", "San Jose Sharks", "Seattle Kraken", "Calgary Flames", "Vancouver Canucks", ]; for (const name of allTeams) { expect(getTeamData(name), `missing team: ${name}`).toBeDefined(); } }); }); // ─── eloWinProbability ──────────────────────────────────────────────────────── describe("eloWinProbability (PARITY_FACTOR = 1000)", () => { it("returns 0.5 for equal Elo ratings", () => { expect(eloWinProbability(1500, 1500)).toBeCloseTo(0.5, 6); }); it("favors the higher-rated team", () => { expect(eloWinProbability(1594, 1500)).toBeGreaterThan(0.5); expect(eloWinProbability(1500, 1594)).toBeLessThan(0.5); }); it("is anti-symmetric: P(A>B) + P(B>A) = 1", () => { const p = eloWinProbability(1580, 1520); expect(p + eloWinProbability(1520, 1580)).toBeCloseTo(1.0, 10); }); it("a 100-pt gap gives ~55.7% win prob per game", () => { // At 1000: P = 1 / (1 + 10^(-100/1000)) ≈ 0.557 const p = eloWinProbability(1600, 1500); expect(p).toBeCloseTo(0.557, 2); }); it("a 200-pt gap gives ~61.3% win prob per game", () => { // At 1000: P = 1 / (1 + 10^(-200/1000)) ≈ 0.613 const p = eloWinProbability(1700, 1500); expect(p).toBeCloseTo(0.613, 2); }); }); // ─── Seeding probabilities sanity checks ───────────────────────────────────── describe("team seeding probabilities", () => { it("playoff probability sums to ≤ 1.0 per team", () => { const teamNames = [ "Colorado Avalanche", "Dallas Stars", "Minnesota Wild", "Utah Mammoth", "Carolina Hurricanes", "Buffalo Sabres", "Tampa Bay Lightning", ]; for (const name of teamNames) { const d = getTeamData(name); expect(d).toBeDefined(); const total = (d?.p_div1 ?? 0) + (d?.p_div2 ?? 0) + (d?.p_div3 ?? 0) + (d?.p_wc1 ?? 0) + (d?.p_wc2 ?? 0); expect(total, `${name} playoff prob > 1`).toBeLessThanOrEqual(1.001); } }); it("eliminated teams have no seeding probability keys", () => { const eliminated = ["Toronto Maple Leafs", "New York Rangers", "Chicago Blackhawks", "Vancouver Canucks"]; for (const name of eliminated) { const d = getTeamData(name); expect(d).toBeDefined(); const total = (d?.p_div1 ?? 0) + (d?.p_div2 ?? 0) + (d?.p_div3 ?? 0) + (d?.p_wc1 ?? 0) + (d?.p_wc2 ?? 0); expect(total, `${name} should have 0 playoff probability`).toBe(0); } }); it("division leaders have the highest p_div1 in their division", () => { // COL should dominate Central div1 const col = getTeamData("Colorado Avalanche"); const dal = getTeamData("Dallas Stars"); expect((col?.p_div1 ?? 0)).toBeGreaterThan(dal?.p_div1 ?? 0); // CAR should dominate Metro div1 const car = getTeamData("Carolina Hurricanes"); const cbj = getTeamData("Columbus Blue Jackets"); expect((car?.p_div1 ?? 0)).toBeGreaterThan(cbj?.p_div1 ?? 0); }); });