diff --git a/e2e/cucumber/features/bracket-visualization.feature b/e2e/cucumber/features/bracket-visualization.feature
new file mode 100644
index 0000000..85b1e9e
--- /dev/null
+++ b/e2e/cucumber/features/bracket-visualization.feature
@@ -0,0 +1,37 @@
+Feature: Bracket Visualization
+ As a tournament admin
+ I want to see a visual bracket of the tournament schedule
+ So that I can track tournament progress at a glance
+
+ @happy-path @tournament @issue-8
+ Scenario: Tournament admin views bracket with a generated schedule
+ Given I am logged in as a tournament admin
+ And a tournament exists with 4 teams
+ When I go to the tournament schedule page
+ And I click the "Generate Schedule" button
+ Then I should see "Generated"
+ When I go to the tournament detail page
+ And I click the "Bracket" tab
+ Then I should see "Tournament Bracket"
+ And I should see "Round 1"
+ And I should see "Round 2"
+ And I should see "Round 3"
+ And I should see bracket matchup cards
+
+ @happy-path @tournament @issue-8
+ Scenario: Bracket shows team names in matchup cards
+ Given I am logged in as a tournament admin
+ And a tournament exists with 4 teams
+ When I go to the tournament schedule page
+ And I click the "Generate Schedule" button
+ Then I should see "Generated"
+ When I go to the tournament detail page
+ And I click the "Bracket" tab
+ Then I should see bracket matchup cards with team names
+
+ @happy-path @tournament @issue-8
+ Scenario: Bracket tab is not visible without a schedule
+ Given I am logged in as a tournament admin
+ And a tournament exists with 4 teams
+ When I go to the tournament detail page
+ Then I should not see the "Bracket" tab
diff --git a/e2e/cucumber/step-definitions/common-steps.ts b/e2e/cucumber/step-definitions/common-steps.ts
index a27c840..2294c0a 100644
--- a/e2e/cucumber/step-definitions/common-steps.ts
+++ b/e2e/cucumber/step-definitions/common-steps.ts
@@ -748,3 +748,44 @@ Then('I should not see the viewing as banner', async function () {
await expect(banner).not.toBeVisible({ timeout: 3000 });
console.log('🌍 Verified viewing as banner is not visible');
});
+
+// Bracket Visualization Steps
+When('I go to the tournament detail page', async function () {
+ const tournamentId = world.tournament?.id || 1;
+ await world.page.goto(`${world.baseURL}/admin/tournaments/${tournamentId}`);
+ await world.page.waitForLoadState('networkidle');
+ await world.page.waitForTimeout(500);
+ console.log(`🌍 Navigated to tournament detail page: ${tournamentId}`);
+});
+
+When('I click the {string} tab', async function (tabName: string) {
+ const tab = world.page.locator(`button:has-text("${tabName}")`);
+ await tab.click();
+ await world.page.waitForTimeout(500);
+ console.log(`🌍 Clicked "${tabName}" tab`);
+});
+
+Then('I should see bracket matchup cards', async function () {
+ const cards = world.page.locator('[data-testid="bracket-matchup"]');
+ const count = await cards.count();
+ expect(count).toBeGreaterThan(0);
+ console.log(`🌍 Found ${count} bracket matchup cards`);
+});
+
+Then('I should see bracket matchup cards with team names', async function () {
+ const cards = world.page.locator('[data-testid="bracket-matchup"]');
+ const count = await cards.count();
+ expect(count).toBeGreaterThan(0);
+
+ const firstCard = cards.first();
+ const text = await firstCard.textContent();
+ expect(text).toBeTruthy();
+ expect(text!.length).toBeGreaterThan(2);
+ console.log(`🌍 Verified bracket matchup cards have team names`);
+});
+
+Then('I should not see the {string} tab', async function (tabName: string) {
+ const tab = world.page.locator(`button:has-text("${tabName}")`);
+ await expect(tab).not.toBeVisible({ timeout: 3000 });
+ console.log(`🌍 Verified "${tabName}" tab is not visible`);
+});
diff --git a/src/app/admin/tournaments/[id]/page.tsx b/src/app/admin/tournaments/[id]/page.tsx
index 3a936bb..77ff413 100644
--- a/src/app/admin/tournaments/[id]/page.tsx
+++ b/src/app/admin/tournaments/[id]/page.tsx
@@ -7,6 +7,7 @@ import Navigation from "@/components/Navigation"
import TeamsSection from "@/components/TeamsSection"
import { DeleteTournamentButton } from "@/components/DeleteTournamentButton"
import { ScheduleGenerator } from "@/components/ScheduleGenerator"
+import { BracketVisualization } from "@/components/BracketVisualization"
import MatchEditor from "@/components/MatchEditor"
interface PageProps {
@@ -420,6 +421,11 @@ export default function TournamentDetailPage({ params }: PageProps) {
)
+ case "bracket":
+ return (
+
No schedule generated yet. Generate a schedule to see the bracket.
+