* Add oxlint and fix all lint errors - Install oxlint, add .oxlintrc.json with rules for TypeScript/React - Add npm run lint / lint:fix scripts - Add Claude PostToolUse hook to run oxlint on every edited file - Fix 101 errors: unused vars/imports, eqeqeq, prefer-const, no-new-array - Fix no-array-index-key (use stable keys or suppress positional cases) - Fix exhaustive-deps missing dependency in useEffect - Promote exhaustive-deps and no-array-index-key to errors - Fix Map.get() !== null bug in $leagueId.server.ts (should be !== undefined) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Fix no-explicit-any warnings and upgrade tsconfig to ES2023 - Replace all `any` types with proper types or `unknown` across ~20 files - Add typed socket payload interfaces in draft route and useDraftSocket - Use any[] with eslint-disable for socket.io callbacks (legitimate escape hatch) - Bump all tsconfigs from ES2022 → ES2023 to support toSorted/toReversed - Fix cascading type errors uncovered by removing any: Map.get narrowing, participant relation types, ChartDataPoint, Partial<NewSeason> indexing - Add ParticipantResultWithParticipant type to participant-result model - Fix test fixtures to match updated interfaces (DraftCell, ParticipantResult) - Fix duplicate getQPStandings import in sportsSeasonId.server.ts Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Promote no-explicit-any to error Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
184 lines
7 KiB
TypeScript
184 lines
7 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import {
|
|
SIMPLE_4,
|
|
SIMPLE_8,
|
|
SIMPLE_16,
|
|
SIMPLE_32,
|
|
NCAA_68,
|
|
NFL_14,
|
|
getBracketTemplate,
|
|
getScoringRoundType,
|
|
} from "~/lib/bracket-templates";
|
|
|
|
describe("Bracket Templates", () => {
|
|
describe("Template Structure", () => {
|
|
it("SIMPLE_4 has correct structure", () => {
|
|
expect(SIMPLE_4.id).toBe("simple_4");
|
|
expect(SIMPLE_4.totalTeams).toBe(4);
|
|
expect(SIMPLE_4.rounds).toHaveLength(2);
|
|
expect(SIMPLE_4.scoringStartsAtRound).toBe("Semifinals");
|
|
expect(SIMPLE_4.rounds.every((r) => r.isScoring)).toBe(true);
|
|
});
|
|
|
|
it("SIMPLE_8 has correct structure", () => {
|
|
expect(SIMPLE_8.id).toBe("simple_8");
|
|
expect(SIMPLE_8.totalTeams).toBe(8);
|
|
expect(SIMPLE_8.rounds).toHaveLength(3);
|
|
expect(SIMPLE_8.scoringStartsAtRound).toBe("Quarterfinals");
|
|
expect(SIMPLE_8.rounds.every((r) => r.isScoring)).toBe(true);
|
|
});
|
|
|
|
it("SIMPLE_16 has correct structure", () => {
|
|
expect(SIMPLE_16.id).toBe("simple_16");
|
|
expect(SIMPLE_16.totalTeams).toBe(16);
|
|
expect(SIMPLE_16.rounds).toHaveLength(4);
|
|
expect(SIMPLE_16.scoringStartsAtRound).toBe("Quarterfinals");
|
|
|
|
// First round doesn't score
|
|
expect(SIMPLE_16.rounds[0].isScoring).toBe(false);
|
|
expect(SIMPLE_16.rounds[0].name).toBe("Round of 16");
|
|
|
|
// Quarterfinals and beyond score
|
|
expect(SIMPLE_16.rounds[1].isScoring).toBe(true);
|
|
expect(SIMPLE_16.rounds[2].isScoring).toBe(true);
|
|
expect(SIMPLE_16.rounds[3].isScoring).toBe(true);
|
|
});
|
|
|
|
it("SIMPLE_32 has correct structure", () => {
|
|
expect(SIMPLE_32.id).toBe("simple_32");
|
|
expect(SIMPLE_32.totalTeams).toBe(32);
|
|
expect(SIMPLE_32.rounds).toHaveLength(5);
|
|
expect(SIMPLE_32.scoringStartsAtRound).toBe("Quarterfinals");
|
|
|
|
// First two rounds don't score
|
|
expect(SIMPLE_32.rounds[0].isScoring).toBe(false);
|
|
expect(SIMPLE_32.rounds[1].isScoring).toBe(false);
|
|
|
|
// Quarterfinals and beyond score
|
|
expect(SIMPLE_32.rounds[2].isScoring).toBe(true);
|
|
expect(SIMPLE_32.rounds[3].isScoring).toBe(true);
|
|
expect(SIMPLE_32.rounds[4].isScoring).toBe(true);
|
|
});
|
|
|
|
it("NCAA_68 has correct structure", () => {
|
|
expect(NCAA_68.id).toBe("ncaa_68");
|
|
expect(NCAA_68.totalTeams).toBe(68);
|
|
expect(NCAA_68.rounds).toHaveLength(7);
|
|
expect(NCAA_68.scoringStartsAtRound).toBe("Elite Eight");
|
|
|
|
// First Four through Sweet Sixteen don't score
|
|
expect(NCAA_68.rounds[0].name).toBe("First Four");
|
|
expect(NCAA_68.rounds[0].isScoring).toBe(false);
|
|
expect(NCAA_68.rounds[1].name).toBe("Round of 64");
|
|
expect(NCAA_68.rounds[1].isScoring).toBe(false);
|
|
expect(NCAA_68.rounds[2].name).toBe("Round of 32");
|
|
expect(NCAA_68.rounds[2].isScoring).toBe(false);
|
|
expect(NCAA_68.rounds[3].name).toBe("Sweet Sixteen");
|
|
expect(NCAA_68.rounds[3].isScoring).toBe(false);
|
|
|
|
// Elite Eight and beyond score
|
|
expect(NCAA_68.rounds[4].name).toBe("Elite Eight");
|
|
expect(NCAA_68.rounds[4].isScoring).toBe(true);
|
|
expect(NCAA_68.rounds[5].name).toBe("Final Four");
|
|
expect(NCAA_68.rounds[5].isScoring).toBe(true);
|
|
expect(NCAA_68.rounds[6].name).toBe("Championship");
|
|
expect(NCAA_68.rounds[6].isScoring).toBe(true);
|
|
});
|
|
|
|
it("NFL_14 has correct structure", () => {
|
|
expect(NFL_14.id).toBe("nfl_14");
|
|
expect(NFL_14.totalTeams).toBe(14);
|
|
expect(NFL_14.rounds).toHaveLength(4);
|
|
expect(NFL_14.scoringStartsAtRound).toBe("Divisional");
|
|
|
|
// Wild Card doesn't score
|
|
expect(NFL_14.rounds[0].name).toBe("Wild Card");
|
|
expect(NFL_14.rounds[0].isScoring).toBe(false);
|
|
|
|
// Divisional and beyond score
|
|
expect(NFL_14.rounds[1].name).toBe("Divisional");
|
|
expect(NFL_14.rounds[1].isScoring).toBe(true);
|
|
expect(NFL_14.rounds[2].isScoring).toBe(true);
|
|
expect(NFL_14.rounds[3].isScoring).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe("Round Advancement", () => {
|
|
it("rounds correctly feed into next rounds", () => {
|
|
// 8-team bracket
|
|
expect(SIMPLE_8.rounds[0].feedsInto).toBe("Semifinals");
|
|
expect(SIMPLE_8.rounds[1].feedsInto).toBe("Finals");
|
|
expect(SIMPLE_8.rounds[2].feedsInto).toBe(null);
|
|
|
|
// NCAA bracket
|
|
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).toBe(null);
|
|
});
|
|
});
|
|
|
|
describe("Match Counts", () => {
|
|
it("calculates correct match counts for each round", () => {
|
|
// 16-team bracket
|
|
expect(SIMPLE_16.rounds[0].matchCount).toBe(8); // Round of 16
|
|
expect(SIMPLE_16.rounds[1].matchCount).toBe(4); // QF
|
|
expect(SIMPLE_16.rounds[2].matchCount).toBe(2); // SF
|
|
expect(SIMPLE_16.rounds[3].matchCount).toBe(1); // Finals
|
|
|
|
// NCAA bracket
|
|
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
|
|
expect(NCAA_68.rounds[5].matchCount).toBe(2); // Final Four
|
|
expect(NCAA_68.rounds[6].matchCount).toBe(1); // Championship
|
|
});
|
|
});
|
|
|
|
describe("getBracketTemplate", () => {
|
|
it("returns correct template by id", () => {
|
|
expect(getBracketTemplate("simple_4")).toBe(SIMPLE_4);
|
|
expect(getBracketTemplate("simple_8")).toBe(SIMPLE_8);
|
|
expect(getBracketTemplate("simple_16")).toBe(SIMPLE_16);
|
|
expect(getBracketTemplate("ncaa_68")).toBe(NCAA_68);
|
|
});
|
|
|
|
it("returns undefined for invalid id", () => {
|
|
expect(getBracketTemplate("invalid")).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe("getScoringRoundType", () => {
|
|
it("identifies quarterfinals (4 matches)", () => {
|
|
const type = getScoringRoundType("Quarterfinals", SIMPLE_8);
|
|
expect(type).toBe("quarterfinals");
|
|
});
|
|
|
|
it("identifies semifinals (2 matches)", () => {
|
|
const type = getScoringRoundType("Semifinals", SIMPLE_8);
|
|
expect(type).toBe("semifinals");
|
|
});
|
|
|
|
it("identifies finals (1 match)", () => {
|
|
const type = getScoringRoundType("Finals", SIMPLE_8);
|
|
expect(type).toBe("finals");
|
|
});
|
|
|
|
it("returns null for non-scoring rounds", () => {
|
|
const type = getScoringRoundType("Round of 16", SIMPLE_16);
|
|
expect(type).toBe(null);
|
|
});
|
|
|
|
it("works with NCAA template", () => {
|
|
expect(getScoringRoundType("Elite Eight", NCAA_68)).toBe("quarterfinals");
|
|
expect(getScoringRoundType("Final Four", NCAA_68)).toBe("semifinals");
|
|
expect(getScoringRoundType("Championship", NCAA_68)).toBe("finals");
|
|
expect(getScoringRoundType("Sweet Sixteen", NCAA_68)).toBe(null);
|
|
});
|
|
});
|
|
});
|