brackt/app/models/__tests__/ncaa-68-bracket.test.ts

205 lines
7.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { describe, it, expect } from "vitest";
import { NCAA_68, getScoringRoundType } from "~/lib/bracket-templates";
/**
* NCAA 68 Bracket Unit Tests - Phase 2.8
*
* Tests the NCAA 68 tournament template structure and scoring logic:
* - 68 teams total (60 direct seeds + 8 in First Four)
* - First Four: 4 play-in games (8 teams)
* - Round of 64: 32 games
* - Only Elite Eight and beyond score fantasy points
*/
describe("NCAA 68 Bracket Template - Phase 2.8", () => {
describe("Template Structure", () => {
it("has correct total teams", () => {
expect(NCAA_68.totalTeams).toBe(68);
});
it("has all 7 rounds", () => {
expect(NCAA_68.rounds).toHaveLength(7);
expect(NCAA_68.rounds[0].name).toBe("First Four");
expect(NCAA_68.rounds[1].name).toBe("Round of 64");
expect(NCAA_68.rounds[2].name).toBe("Round of 32");
expect(NCAA_68.rounds[3].name).toBe("Sweet Sixteen");
expect(NCAA_68.rounds[4].name).toBe("Elite Eight");
expect(NCAA_68.rounds[5].name).toBe("Final Four");
expect(NCAA_68.rounds[6].name).toBe("Championship");
});
it("has correct match counts per round", () => {
expect(NCAA_68.rounds[0].matchCount).toBe(4); // First Four
expect(NCAA_68.rounds[1].matchCount).toBe(32); // Round of 64
expect(NCAA_68.rounds[2].matchCount).toBe(16); // Round of 32
expect(NCAA_68.rounds[3].matchCount).toBe(8); // Sweet Sixteen
expect(NCAA_68.rounds[4].matchCount).toBe(4); // Elite Eight (Quarterfinals)
expect(NCAA_68.rounds[5].matchCount).toBe(2); // Final Four (Semifinals)
expect(NCAA_68.rounds[6].matchCount).toBe(1); // Championship (Finals)
});
it("has correct round feeding structure", () => {
expect(NCAA_68.rounds[0].feedsInto).toBe("Round of 64");
expect(NCAA_68.rounds[1].feedsInto).toBe("Round of 32");
expect(NCAA_68.rounds[2].feedsInto).toBe("Sweet Sixteen");
expect(NCAA_68.rounds[3].feedsInto).toBe("Elite Eight");
expect(NCAA_68.rounds[4].feedsInto).toBe("Final Four");
expect(NCAA_68.rounds[5].feedsInto).toBe("Championship");
expect(NCAA_68.rounds[6].feedsInto).toBeNull(); // Championship has no next round
});
});
describe("Scoring Configuration", () => {
it("marks scoring to start at Elite Eight", () => {
expect(NCAA_68.scoringStartsAtRound).toBe("Elite Eight");
});
it("marks First Four as non-scoring", () => {
const firstFour = NCAA_68.rounds[0];
expect(firstFour.name).toBe("First Four");
expect(firstFour.isScoring).toBe(false);
});
it("marks Round of 64 as non-scoring", () => {
const roundOf64 = NCAA_68.rounds[1];
expect(roundOf64.name).toBe("Round of 64");
expect(roundOf64.isScoring).toBe(false);
});
it("marks Round of 32 as non-scoring", () => {
const roundOf32 = NCAA_68.rounds[2];
expect(roundOf32.name).toBe("Round of 32");
expect(roundOf32.isScoring).toBe(false);
});
it("marks Sweet Sixteen as non-scoring", () => {
const sweetSixteen = NCAA_68.rounds[3];
expect(sweetSixteen.name).toBe("Sweet Sixteen");
expect(sweetSixteen.isScoring).toBe(false);
});
it("marks Elite Eight as scoring (Quarterfinals)", () => {
const eliteEight = NCAA_68.rounds[4];
expect(eliteEight.name).toBe("Elite Eight");
expect(eliteEight.isScoring).toBe(true);
});
it("marks Final Four as scoring (Semifinals)", () => {
const finalFour = NCAA_68.rounds[5];
expect(finalFour.name).toBe("Final Four");
expect(finalFour.isScoring).toBe(true);
});
it("marks Championship as scoring (Finals)", () => {
const championship = NCAA_68.rounds[6];
expect(championship.name).toBe("Championship");
expect(championship.isScoring).toBe(true);
});
it("has exactly 3 scoring rounds (Elite Eight, Final Four, Championship)", () => {
const scoringRounds = NCAA_68.rounds.filter((r) => r.isScoring);
expect(scoringRounds).toHaveLength(3);
expect(scoringRounds[0].name).toBe("Elite Eight");
expect(scoringRounds[1].name).toBe("Final Four");
expect(scoringRounds[2].name).toBe("Championship");
});
it("has exactly 4 non-scoring rounds (FF, R64, R32, S16)", () => {
const nonScoringRounds = NCAA_68.rounds.filter((r) => !r.isScoring);
expect(nonScoringRounds).toHaveLength(4);
});
});
describe("Scoring Round Types", () => {
it("identifies Elite Eight as quarterfinals", () => {
const type = getScoringRoundType("Elite Eight", NCAA_68);
expect(type).toBe("quarterfinals");
});
it("identifies Final Four as semifinals", () => {
const type = getScoringRoundType("Final Four", NCAA_68);
expect(type).toBe("semifinals");
});
it("identifies Championship as finals", () => {
const type = getScoringRoundType("Championship", NCAA_68);
expect(type).toBe("finals");
});
it("returns null for non-scoring rounds", () => {
expect(getScoringRoundType("First Four", NCAA_68)).toBeNull();
expect(getScoringRoundType("Round of 64", NCAA_68)).toBeNull();
expect(getScoringRoundType("Round of 32", NCAA_68)).toBeNull();
expect(getScoringRoundType("Sweet Sixteen", NCAA_68)).toBeNull();
});
});
describe("Tournament Math", () => {
it("has correct number of total matches", () => {
// 4 + 32 + 16 + 8 + 4 + 2 + 1 = 67 total matches
const totalMatches = NCAA_68.rounds.reduce((sum, round) => sum + round.matchCount, 0);
expect(totalMatches).toBe(67);
});
it("eliminates 60 teams before Elite Eight (4+32+16+8)", () => {
const nonScoringRounds = NCAA_68.rounds.filter((r) => !r.isScoring);
const teamsEliminatedBeforeEliteEight = nonScoringRounds.reduce(
(sum, round) => sum + round.matchCount,
0
);
expect(teamsEliminatedBeforeEliteEight).toBe(60); // 4+32+16+8
});
it("has 8 teams in Elite Eight (top 8 scoring)", () => {
const eliteEightRound = NCAA_68.rounds.find((r) => r.name === "Elite Eight");
const teamsInEliteEight = eliteEightRound!.matchCount * 2;
expect(teamsInEliteEight).toBe(8);
});
it("verifies only 8 teams score fantasy points (Q18)", () => {
// Elite Eight has 4 matches = 8 teams
// These are the ONLY teams that can score fantasy points
const scoringRounds = NCAA_68.rounds.filter((r) => r.isScoring);
const eliteEightMatches = scoringRounds[0].matchCount;
const scoringTeamsCount = eliteEightMatches * 2;
expect(scoringTeamsCount).toBe(8);
});
});
describe("Phase 2.8 Requirements", () => {
it("meets requirement: 68 total teams", () => {
expect(NCAA_68.totalTeams).toBe(68);
});
it("meets requirement: 4 First Four play-in games", () => {
const firstFour = NCAA_68.rounds[0];
expect(firstFour.matchCount).toBe(4);
});
it("meets requirement: Only Elite Eight and beyond score points", () => {
const scoringRoundNames = NCAA_68.rounds
.filter((r) => r.isScoring)
.map((r) => r.name);
expect(scoringRoundNames).toEqual(["Elite Eight", "Final Four", "Championship"]);
});
it("meets requirement: Early elimination = 0 points (per Q20)", () => {
const firstFour = NCAA_68.rounds[0];
const roundOf64 = NCAA_68.rounds[1];
const roundOf32 = NCAA_68.rounds[2];
const sweetSixteen = NCAA_68.rounds[3];
expect(firstFour.isScoring).toBe(false); // 0 points
expect(roundOf64.isScoring).toBe(false); // 0 points
expect(roundOf32.isScoring).toBe(false); // 0 points
expect(sweetSixteen.isScoring).toBe(false); // 0 points
});
it("verifies total participants: 60 direct + 8 First Four", () => {
const firstFourTeams = 4 * 2; // 4 games × 2 teams = 8 teams
const directSeeds = 68 - firstFourTeams; // 60 teams directly seeded
expect(directSeeds).toBe(60);
expect(firstFourTeams).toBe(8);
expect(directSeeds + firstFourTeams).toBe(68);
});
});
});