import { chromium } from "playwright"; import fs from "node:fs"; const OUT = "docs/screenshots"; const BASE = "http://localhost:3011"; fs.mkdirSync(OUT, { recursive: true }); const browser = await chromium.launch(); const errs = []; async function session(width, height, theme) { const ctx = await browser.newContext({ viewport: { width, height }, deviceScaleFactor: 2, colorScheme: theme === "light" ? "light" : "dark", locale: "de-DE", timezoneId: "Europe/Berlin", }); await ctx.addInitScript((mode) => localStorage.setItem("flimmer-theme", mode), theme); // Der Entwicklungs-Indikator von Next hat in einer Anleitung nichts verloren. await ctx.addStyleTag?.({ content: "nextjs-portal { display: none !important; }" }); const page = await ctx.newPage(); await page.addStyleTag({ content: "nextjs-portal { display: none !important; }" }).catch(() => {}); page.on("pageerror", (e) => errs.push(String(e).slice(0, 160))); return { ctx, page }; } async function login(page) { await page.goto(`${BASE}/anmelden`); await page.fill("#email", "demo@flimmer.local"); await page.fill("#password", "flimmer-demo-2026"); await Promise.all([page.waitForURL(`${BASE}/`), page.click("button[type=submit]")]); } async function shot(page, name, url, opts = {}) { await page.goto(`${BASE}${url}`, { waitUntil: "networkidle" }); await page.addStyleTag({ content: "nextjs-portal { display: none !important; }" }).catch(() => {}); await page.waitForTimeout(opts.wait ?? 900); if (opts.before) await opts.before(page); await page.screenshot({ path: `${OUT}/${name}.png`, fullPage: Boolean(opts.full) }); console.log(" ", name); } // --- Anmeldung (ohne Sitzung) --- { const { ctx, page } = await session(1280, 800, "dark"); await shot(page, "01-anmeldung", "/anmelden"); await ctx.close(); } // --- Angemeldet, dunkel --- { const { ctx, page } = await session(1400, 900, "dark"); await login(page); await shot(page, "02-uebersicht", "/", { full: true }); await shot(page, "03-suche", "/suche?q=sternenpfad"); await shot(page, "05-bibliothek", "/bibliothek"); await shot(page, "09-kalender", "/kalender"); await shot(page, "10-statistik", "/statistik", { full: true }); await shot(page, "11-einstellungen", "/einstellungen"); await shot(page, "12-benachrichtigungen", "/einstellungen/benachrichtigungen"); await shot(page, "13-api", "/einstellungen/api"); await shot(page, "14-daten", "/einstellungen/daten"); await shot(page, "15-verwaltung", "/verwaltung", { full: true }); await shot(page, "16-papierkorb", "/papierkorb"); // Detailseite und Universum brauchen IDs aus der Bibliothek await page.goto(`${BASE}/bibliothek?q=nordlicht`, { waitUntil: "networkidle" }); const titleHref = await page.locator("a[href^='/titel/']").first().getAttribute("href"); if (titleHref) await shot(page, "04-serie", titleHref, { full: true }); await page.goto(`${BASE}/universen`, { waitUntil: "networkidle" }); await shot(page, "06-universen", "/universen"); const uniHref = await page.locator("a[href^='/universen/']").first().getAttribute("href"); if (uniHref) await shot(page, "07-universum", uniHref, { full: true }); await ctx.close(); } // --- Hell --- { const { ctx, page } = await session(1400, 900, "light"); await login(page); await shot(page, "08-hell", "/bibliothek"); await ctx.close(); } // --- Mobil --- { const { ctx, page } = await session(430, 900, "dark"); await login(page); await shot(page, "17-mobil-uebersicht", "/"); await shot(page, "18-mobil-serie", "/bibliothek"); await ctx.close(); } console.log("Fehler:", errs.length ? [...new Set(errs)].slice(0, 5) : "keine"); await browser.close();