const { test, expect } = require('@playwright/test'); const TEST_EMAIL = process.env.TEST_EMAIL || 'lars@stommer.com'; const TEST_PASSWORD = process.env.TEST_PASSWORD || '12345678'; /** Primärer Submit auf der Login-Seite (nicht den Tab "Login" vs. "Registrieren"). */ async function submitLoginForm(page) { await page.getByRole('button', { name: 'Anmelden' }).click(); } async function login(page) { await page.goto('/'); await page.waitForLoadState('networkidle'); // Warte bis Login-Seite geladen ist await page.waitForSelector('input[type="email"]', { timeout: 10000 }); await page.fill('input[type="email"]', TEST_EMAIL); await page.fill('input[type="password"]', TEST_PASSWORD); await submitLoginForm(page); await page.waitForLoadState('networkidle'); } test('1. Login funktioniert', async ({ page }) => { await page.goto('/'); await page.waitForSelector('input[type="email"]', { timeout: 10000 }); await page.fill('input[type="email"]', TEST_EMAIL); await page.fill('input[type="password"]', TEST_PASSWORD); await submitLoginForm(page); await page.waitForLoadState('networkidle'); // Nach Login soll der Tab "Login" (Moduswahl) verschwinden — nicht der Submit "Anmelden" const loginButton = page.locator('button:has-text("Login")'); await expect(loginButton).toHaveCount(0, { timeout: 10000 }); await page.screenshot({ path: 'screenshots/01-nach-login.png' }); console.log('✓ Login erfolgreich'); }); test('2. Dashboard lädt ohne Fehler', async ({ page }) => { await login(page); // Warte bis Spinner verschwunden await expect(page.locator('.spinner')).toHaveCount(0, { timeout: 10000 }); // Prüfe ob Dashboard-Inhalt da ist await expect(page.locator('text=Willkommen')).toBeVisible({ timeout: 5000 }); await page.screenshot({ path: 'screenshots/02-dashboard.png' }); console.log('✓ Dashboard OK'); }); test('3. Navigation zu Übungen', async ({ page }) => { await login(page); // Bottom-Nav: Übungen klicken await page.click('text=Übungen'); await page.waitForLoadState('networkidle'); // Prüfe ob Übungen-Seite geladen await expect(page.locator('h1, h2, .page-title')).toContainText(/übungen/i, { timeout: 5000 }); await page.screenshot({ path: 'screenshots/03-uebungen.png' }); console.log('✓ Übungen-Seite erreichbar'); }); test('4. Navigation zu Vereine', async ({ page }) => { await login(page); // Bottom-Nav: Vereine klicken await page.click('text=Vereine'); await page.waitForLoadState('networkidle'); // Prüfe ob Vereine-Seite geladen await expect(page.locator('h1, h2, .page-title')).toContainText(/vereine|clubs/i, { timeout: 5000 }); await page.screenshot({ path: 'screenshots/04-vereine.png' }); console.log('✓ Vereine-Seite erreichbar'); }); test('5. Desktop-Sidebar sichtbar (Desktop)', async ({ page }) => { // Desktop-Viewport await page.setViewportSize({ width: 1280, height: 800 }); await login(page); // Prüfe ob Desktop-Sidebar existiert const sidebar = page.locator('.desktop-sidebar'); await expect(sidebar).toBeVisible({ timeout: 5000 }); await page.screenshot({ path: 'screenshots/05-desktop-sidebar.png' }); console.log('✓ Desktop-Sidebar sichtbar'); }); test('6. Bottom-Nav sichtbar (Mobile)', async ({ page }) => { // Mobile-Viewport await page.setViewportSize({ width: 390, height: 844 }); await login(page); // Prüfe ob Bottom-Nav existiert const bottomNav = page.locator('.bottom-nav'); await expect(bottomNav).toBeVisible({ timeout: 5000 }); await page.screenshot({ path: 'screenshots/06-mobile-bottom-nav.png' }); console.log('✓ Bottom-Nav sichtbar'); }); test('7. Session-Persistenz nach Reload', async ({ page }) => { await login(page); // Warte auf Dashboard await expect(page.locator('.spinner')).toHaveCount(0, { timeout: 10000 }); // Reload await page.reload(); await page.waitForLoadState('networkidle'); // Sollte NICHT zur Login-Seite redirecten const loginButton = page.locator('button:has-text("Login")'); await expect(loginButton).toHaveCount(0, { timeout: 5000 }); await page.screenshot({ path: 'screenshots/07-nach-reload.png' }); console.log('✓ Session bleibt nach Reload erhalten'); }); test('8. Keine kritischen Console-Fehler', async ({ page }) => { const errors = []; page.on('console', msg => { if (msg.type() === 'error') errors.push(msg.text()); }); await login(page); await page.waitForLoadState('networkidle'); // Filtere unkritische Fehler const kritisch = errors.filter(e => !e.includes('favicon') && !e.includes('sourceMap') && !e.includes('404') && !e.includes('vite.svg') ); if (kritisch.length > 0) { console.log('⚠ Console-Fehler:', kritisch.join(', ')); } else { console.log('✓ Keine kritischen Console-Fehler'); } expect(kritisch.length).toBe(0); });