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 }); // Zwei verschiedene "Willkommen"-Texte im Dashboard → kein ambiguity locator('text=Willkommen') await expect( page.getByRole('heading', { name: /Willkommen bei Shinkan/i }), ).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); // Bei Viewport ≥1024px ist .bottom-nav versteckt — Mobile garantieren wie in playwright.config.js await page.setViewportSize({ width: 390, height: 844 }); // Desktop-Sidebar enthält ebenfalls Übungen – nur Mobile-Bottom-Nav klicken (sichtbarer Link) await page.locator('.bottom-nav a[href="/exercises"]').click(); 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); await page.setViewportSize({ width: 390, height: 844 }); await page.locator('.bottom-nav a[href="/clubs"]').click(); 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); await expect(page.locator('.spinner')).toHaveCount(0, { timeout: 10000 }); await page.reload({ waitUntil: 'domcontentloaded' }); await page.waitForLoadState('networkidle'); // Auth lädt erst nach Spinner – nicht auf /login stranden (stabiler als Button „Login“-Tab auf Login-Screen) await expect(page.locator('.spinner')).toHaveCount(0, { timeout: 20000 }); await expect(page).not.toHaveURL('**/login', { timeout: 20000 }); await expect(page.locator('h1').filter({ hasText: /^Dashboard$/ })).toBeVisible({ timeout: 10000, }); 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); });