From 9f9efc2bc07810d2e06b37bad94e5922681eadef Mon Sep 17 00:00:00 2001
From: nsfisis <nsfisis@gmail.com>
Date: Wed, 18 Feb 2026 22:38:15 +0900
Subject: feat: refactor tournament to generic DB-backed N-person bracket

Replace hardcoded 6-person tournament with a generic single-elimination
bracket system backed by new DB tables (tournaments, tournament_entries,
tournament_matches). Includes admin CRUD, standard seeding algorithm,
bye handling, and a CSS Grid bracket renderer on the frontend.

Add comprehensive tests for backend API/admin handlers, seeding logic,
and frontend bracket component.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---
 frontend/app/pages/TournamentPage.test.tsx | 60 ++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)
 create mode 100644 frontend/app/pages/TournamentPage.test.tsx

(limited to 'frontend/app/pages/TournamentPage.test.tsx')

diff --git a/frontend/app/pages/TournamentPage.test.tsx b/frontend/app/pages/TournamentPage.test.tsx
new file mode 100644
index 0000000..3c6f116
--- /dev/null
+++ b/frontend/app/pages/TournamentPage.test.tsx
@@ -0,0 +1,60 @@
+/**
+ * @vitest-environment jsdom
+ */
+import { cleanup, render, screen } from "@testing-library/react";
+import { afterEach, describe, expect, test } from "vitest";
+import TournamentPage, { standardBracketSeedsForTest } from "./TournamentPage";
+
+afterEach(() => {
+	cleanup();
+});
+
+describe("standardBracketSeeds", () => {
+	test("bracket_size=2 returns [1, 2]", () => {
+		const seeds = standardBracketSeedsForTest(2);
+		expect(seeds).toEqual([1, 2]);
+	});
+
+	test("bracket_size=4 returns [1, 4, 2, 3]", () => {
+		const seeds = standardBracketSeedsForTest(4);
+		expect(seeds).toEqual([1, 4, 2, 3]);
+	});
+
+	test("bracket_size=8 returns [1, 8, 4, 5, 2, 7, 3, 6]", () => {
+		const seeds = standardBracketSeedsForTest(8);
+		expect(seeds).toEqual([1, 8, 4, 5, 2, 7, 3, 6]);
+	});
+
+	test("all seeds present for size 16", () => {
+		const seeds = standardBracketSeedsForTest(16);
+		expect(seeds).toHaveLength(16);
+		const sorted = [...seeds].sort((a, b) => a - b);
+		expect(sorted).toEqual(Array.from({ length: 16 }, (_, i) => i + 1));
+	});
+
+	test("seed 1 and seed 2 on opposite sides for size 8", () => {
+		const seeds = standardBracketSeedsForTest(8);
+		const pos1 = seeds.indexOf(1);
+		const pos2 = seeds.indexOf(2);
+		// Seed 1 in first half (0-3), Seed 2 in second half (4-7)
+		expect(pos1).toBeLessThan(4);
+		expect(pos2).toBeGreaterThanOrEqual(4);
+	});
+});
+
+describe("TournamentPage", () => {
+	test("shows loading state initially", () => {
+		render(<TournamentPage tournamentId="1" />);
+		expect(screen.getByText("Loading...")).toBeDefined();
+	});
+
+	test("shows error for invalid tournament ID", () => {
+		render(<TournamentPage tournamentId="abc" />);
+		expect(screen.getByText("Invalid tournament ID")).toBeDefined();
+	});
+
+	test("shows error for zero tournament ID", () => {
+		render(<TournamentPage tournamentId="0" />);
+		expect(screen.getByText("Invalid tournament ID")).toBeDefined();
+	});
+});
-- 
cgit v1.3.1

