/** * Issue #22: Team Configuration Options * Acceptance Test: Tournament Creation with Team Configuration * * User Story: As a tournament admin, I want to configure team creation options for round robin tournaments */ import { test, expect } from '@playwright/test'; import { prisma } from '@/lib/prisma'; const BASE_URL = process.env.CI ? 'https://euchre-ci.notsosm.art' : 'http://localhost:3000'; function getTestCredentials() { const timestamp = Date.now(); return { email: `config-admin-${timestamp}@example.com`, password: 'AdminPassword123!', name: `Config Admin ${timestamp}`, }; } test.describe.serial('Issue #22: Team Configuration', () => { let testEmail: string; let testPassword: string; let tournamentId: number; test.beforeAll(async () => { const credentials = getTestCredentials(); testEmail = credentials.email; testPassword = credentials.password; // Create admin user via API const response = await fetch(`${BASE_URL}/api/auth/sign-up/email`, { method: 'POST', headers: { 'Content-Type': 'application/json', Origin: BASE_URL, }, body: JSON.stringify({ email: testEmail, password: testPassword, name: credentials.name, }), }); console.log('Config test user creation response:', response.status); // Update user to club_admin role const user = await prisma.user.findUnique({ where: { email: testEmail }, }); if (user) { await prisma.user.update({ where: { id: user.id }, data: { role: 'club_admin' }, }); } }); test.afterAll(async () => { try { // Clean up tournament if created if (tournamentId) { await prisma.bracketMatchup.deleteMany({ where: { eventId: tournamentId } }); await prisma.tournamentRound.deleteMany({ where: { eventId: tournamentId } }); await prisma.eventParticipant.deleteMany({ where: { eventId: tournamentId } }); await prisma.event.delete({ where: { id: tournamentId } }).catch(() => {}); } // Clean up user const user = await prisma.user.findUnique({ where: { email: testEmail } }); if (user) { await prisma.user.delete({ where: { id: user.id } }); } } catch (error) { console.error('Cleanup error:', error); } }); test('Tournament creation form shows team configuration options', async ({ page }) => { // Login await page.goto('/auth/login'); await page.fill('input[name="email"]', testEmail); await page.fill('input[name="password"]', testPassword); await page.click('button[type="submit"]'); await page.waitForURL(/\/(admin|players)/, { timeout: 10000 }); // Navigate to tournament creation await page.goto('/admin/tournaments/new'); // Select Round Robin format await page.selectOption('select[name="format"]', 'round_robin'); // Check that team configuration section is visible await expect(page.locator('text=Team Configuration')).toBeVisible(); // Check team durability options await expect(page.locator('input[name="teamDurability"][value="permanent"]')).toBeVisible(); await expect(page.locator('input[name="teamDurability"][value="variable"]')).toBeVisible(); await expect(page.locator('input[name="teamDurability"][value="per_round"]')).toBeVisible(); }); test('Create tournament with permanent teams', async ({ page }) => { // Login await page.goto('/auth/login'); await page.fill('input[name="email"]', testEmail); await page.fill('input[name="password"]', testPassword); await page.click('button[type="submit"]'); await page.waitForURL(/\/(admin|players)/, { timeout: 10000 }); // Navigate to tournament creation await page.goto('/admin/tournaments/new'); // Fill in tournament details await page.fill('input[name="name"]', `Test Tournament ${Date.now()}`); await page.selectOption('select[name="format"]', 'round_robin'); // Select permanent teams await page.click('input[name="teamDurability"][value="permanent"]'); // Move to step 2 (Participants) await page.click('button:has-text("Next")'); // Add players using the player creation feature const playerName1 = `Player ${Date.now()}`; const playerName2 = `Player ${Date.now() + 1}`; const playerName3 = `Player ${Date.now() + 2}`; const playerName4 = `Player ${Date.now() + 3}`; // Create first player await page.fill('input[placeholder*="Search"]', playerName1); await page.waitForTimeout(500); await page.click(`text=+ Create "${playerName1}" as new player`); await page.fill('input[placeholder*="Enter player name"]', playerName1); await page.click('button:has-text("Add")'); // Create second player await page.fill('input[placeholder*="Search"]', playerName2); await page.waitForTimeout(500); await page.click(`text=+ Create "${playerName2}" as new player`); await page.fill('input[placeholder*="Enter player name"]', playerName2); await page.click('button:has-text("Add")'); // Create third player await page.fill('input[placeholder*="Search"]', playerName3); await page.waitForTimeout(500); await page.click(`text=+ Create "${playerName3}" as new player`); await page.fill('input[placeholder*="Enter player name"]', playerName3); await page.click('button:has-text("Add")'); // Create fourth player await page.fill('input[placeholder*="Search"]', playerName4); await page.waitForTimeout(500); await page.click(`text=+ Create "${playerName4}" as new player`); await page.fill('input[placeholder*="Enter player name"]', playerName4); await page.click('button:has-text("Add")'); // Submit the form await page.click('button:has-text("Create Tournament")'); // Wait for redirect to schedule page await page.waitForURL(/\/schedule$/, { timeout: 10000 }); // Verify tournament was created const url = page.url(); const match = url.match(/\/admin\/tournaments\/(\d+)\/schedule/); expect(match).toBeTruthy(); tournamentId = parseInt(match![1]); // Verify team configuration was saved const tournament = await prisma.event.findUnique({ where: { id: tournamentId }, }); expect(tournament).toBeTruthy(); expect(tournament?.teamDurability).toBe('permanent'); }); test('Create tournament with variable teams and partner rotation', async ({ page }) => { // Login await page.goto('/auth/login'); await page.fill('input[name="email"]', testEmail); await page.fill('input[name="password"]', testPassword); await page.click('button[type="submit"]'); await page.waitForURL(/\/(admin|players)/, { timeout: 10000 }); // Navigate to tournament creation await page.goto('/admin/tournaments/new'); // Fill in tournament details await page.fill('input[name="name"]', `Variable Teams Tournament ${Date.now()}`); await page.selectOption('select[name="format"]', 'round_robin'); // Select variable teams await page.click('input[name="teamDurability"][value="variable"]'); // Check that partner rotation options appear await expect(page.locator('text=Partner Rotation Strategy')).toBeVisible(); // Select minimize repeat partners await page.click('input[name="partnerRotation"][value="minimize_repeat"]'); // Move to step 2 (Participants) await page.click('button:has-text("Next")'); // Create players const playerName1 = `VarPlayer ${Date.now()}`; const playerName2 = `VarPlayer ${Date.now() + 1}`; const playerName3 = `VarPlayer ${Date.now() + 2}`; const playerName4 = `VarPlayer ${Date.now() + 3}`; for (const name of [playerName1, playerName2, playerName3, playerName4]) { await page.fill('input[placeholder*="Search"]', name); await page.waitForTimeout(500); await page.click(`text=+ Create "${name}" as new player`); await page.fill('input[placeholder*="Enter player name"]', name); await page.click('button:has-text("Add")'); } // Submit the form await page.click('button:has-text("Create Tournament")'); // Wait for redirect to schedule page await page.waitForURL(/\/schedule$/, { timeout: 10000 }); // Verify tournament was created const url = page.url(); const match = url.match(/\/admin\/tournaments\/(\d+)\/schedule/); expect(match).toBeTruthy(); tournamentId = parseInt(match![1]); // Verify team configuration was saved const tournament = await prisma.event.findUnique({ where: { id: tournamentId }, }); expect(tournament).toBeTruthy(); expect(tournament?.teamDurability).toBe('variable'); expect(tournament?.partnerRotation).toBe('minimize_repeat'); }); test('Edit tournament team configuration', async ({ page }) => { // First create a tournament with default settings const createResponse = await fetch(`${BASE_URL}/api/tournaments`, { method: 'POST', headers: { 'Content-Type': 'application/json', Origin: BASE_URL, }, body: JSON.stringify({ name: `Edit Test Tournament ${Date.now()}`, format: 'round_robin', }), }); const createData = await createResponse.json(); tournamentId = createData.tournament.id; // Login await page.goto('/auth/login'); await page.fill('input[name="email"]', testEmail); await page.fill('input[name="password"]', testPassword); await page.click('button[type="submit"]'); await page.waitForURL(/\/(admin|players)/, { timeout: 10000 }); // Navigate to edit tournament page await page.goto(`/admin/tournaments/${tournamentId}/edit`); // Check that team configuration section is visible await expect(page.locator('text=Team Configuration')).toBeVisible(); // Change team durability to variable await page.click('input[name="teamDurability"][value="variable"]'); // Check that partner rotation options appear await expect(page.locator('text=Partner Rotation Strategy')).toBeVisible(); // Select maximize even partners await page.click('input[name="partnerRotation"][value="maximize_even"]'); // Save changes await page.click('button:has-text("Save Changes")'); // Wait for success message await expect(page.locator('text=Tournament updated successfully!')).toBeVisible(); // Verify changes were saved const tournament = await prisma.event.findUnique({ where: { id: tournamentId }, }); expect(tournament).toBeTruthy(); expect(tournament?.teamDurability).toBe('variable'); expect(tournament?.partnerRotation).toBe('maximize_even'); }); });