// @ts-check const { test, expect } = require('@playwright/test'); /** * Stufe 1 · Glossar-Tooltip-Regression * * Bug 2026-06-10: * - Tooltip-Lib stripte falsch /api statt /php/api → 404 * - Klima-2D/3D fiel mit basePath='' (falsy) auf /geograsim/App zurück * * Dieser Test öffnet die kritischen Stellen und prüft, dass der vom Tooltip * generierte „Voller Glossar-Eintrag →"-Link auf eine 200-URL zeigt. */ const stellen = [ // Klima-2D Onboarding: Sim-eigene Glossar-Logik { name: 'Klima 2D Onboarding', path: 'klima-2d', expectedHrefIncludes: '/glossar?term=' }, // Weltküche: Plattform-Tooltip-Lib { name: 'Weltküche Onboarding', path: 'weltkueche', expectedHrefIncludes: '/glossar?term=' }, ]; for (const stelle of stellen) { test(`Tooltip-Link in ${stelle.name} geht auf 200`, async ({ page }) => { // ?level=1 umgeht das Level-Select-Overlay (Klima 2D/3D) bzw. ist für // andere Sims harmlos await page.goto(`/${stelle.path}?level=1`); await page.waitForLoadState('networkidle', { timeout: 8000 }).catch(() => {}); // Eventuell offene Overlays schließen (Level-Select, Tutorial-Splash) for (const sel of ['#level-select-overlay button', '.ggs-tutorial-skip', '#tutorial-skip']) { try { const el = await page.$(sel); if (el && await el.isVisible()) { await el.click({ timeout: 1500 }); await page.waitForTimeout(300); } } catch (_) {} } // Falls noch ein full-page Overlay sichtbar ist (z. B. Klima-Onboarding) — // ESC tut nichts, also schließen wir es per JS await page.evaluate(() => { document.querySelectorAll('.ggs-overlay.visible, #level-select-overlay.visible').forEach(o => o.classList.remove('visible')); }); // Findet alle Glossar-Trigger im DOM (Klima nutzt data-glossar, Weltküche // nutzt .ggs-g Spans über die Tooltip-Lib) const triggers = await page.$$('[data-glossar]:visible, .ggs-g:visible'); const fallbackTriggers = triggers.length ? triggers : await page.$$('[data-glossar], .ggs-g'); if (fallbackTriggers.length === 0) { console.warn(`[soft] keine Glossar-Trigger in ${stelle.name} gefunden`); return; } // Klick mit Force-Option, falls noch Overlay drüber liegt await fallbackTriggers[0].click({ force: true, timeout: 5000 }).catch(() => {}); await page.waitForTimeout(400); // Link suchen: „Voller Glossar-Eintrag" (Klima) oder „Voller Glossar-Eintrag →" (Lib) const links = await page.locator('a:has-text("Voller Glossar-Eintrag"), a:has-text("Glossar")').all(); let found = false; for (const a of links) { const href = await a.getAttribute('href'); if (href && href.includes(stelle.expectedHrefIncludes)) { // Direkt prüfen, ob die URL 200 antwortet (ohne navigieren) const url = new URL(href, page.url()).toString(); const r = await page.request.get(url); expect(r.status(), `Glossar-Link ${url} antwortet ${r.status()}`).toBeLessThan(400); found = true; break; } } expect(found, `kein „Voller Glossar-Eintrag"-Link gefunden in ${stelle.name}`).toBe(true); }); }