import { mkdir } from 'node:fs/promises' import { test, type Page } from '@playwright/test' /** * Nimmt die Bilder für das Handbuch auf. * * Je Seite vier Bilder: hell und dunkel, Schreibtisch und Handy. Die Uhr steht * auf einem festen Zeitpunkt, damit sich zwischen zwei Läufen nur das ändert, * was sich wirklich geändert hat. */ const ZIEL = 'docs/bilder' const SCHREIBTISCH = { width: 1440, height: 900 } const HANDY = { width: 390, height: 844 } // Dienstag, 17. März 2026, 09:20 Uhr in Berlin. const FESTE_ZEIT = new Date('2026-03-17T08:20:00.000Z') const EMAIL = 'martina.beispiel@planer.invalid' const PASSWORT = 'demo-instanz-nur-fuer-bilder' type Aufnahme = { name: string pfad: string /** Wird vor der Aufnahme ausgeführt, z. B. um ein Formular aufzuklappen. */ vorbereiten?: (seite: Page) => Promise /** * Nur diesen Ausschnitt aufnehmen statt der ganzen Seite. * * Für Themen, die auf einer gemeinsamen Seite wohnen: ein Bild der ganzen * Einstellungsseite zeigt im Handbuchkapitel zu wenig vom Eigentlichen. */ ausschnitt?: string } const AUFNAHMEN: Aufnahme[] = [ { name: 'anmelden', pfad: '/anmelden' }, { name: 'start', pfad: '/' }, { name: 'inbox', pfad: '/inbox' }, { name: 'erfassen', pfad: '/erfassen' }, { name: 'aufgaben', pfad: '/aufgaben' }, { name: 'woche', pfad: '/woche' }, { name: 'projekte', pfad: '/projekte' }, { name: 'ideen', pfad: '/ideen' }, { name: 'bereiche', pfad: '/bereiche' }, { name: 'kalenderkonten', pfad: '/kalenderkonten' }, { name: 'integrationen', pfad: '/integrationen' }, { name: 'einstellungen', pfad: '/einstellungen' }, { name: 'benachrichtigungen', pfad: '/einstellungen', ausschnitt: '[data-bild="benachrichtigungen"]', }, { name: 'api', pfad: '/verwaltung/api' }, { name: 'protokoll', pfad: '/verwaltung/protokoll' }, ] async function anmelden(seite: Page): Promise { await seite.goto('/anmelden') await seite.getByLabel('E-Mail-Adresse').fill(EMAIL) await seite.getByLabel('Passwort').fill(PASSWORT) await seite.getByRole('button', { name: 'Mit Passwort anmelden' }).click() await seite.waitForURL('/') } test.beforeAll(async () => { await mkdir(ZIEL, { recursive: true }) }) for (const schema of ['hell', 'dunkel'] as const) { for (const [geraet, groesse] of [ ['schreibtisch', SCHREIBTISCH], ['handy', HANDY], ] as const) { test(`Bilder: ${schema}, ${geraet}`, async ({ browser }) => { const kontext = await browser.newContext({ viewport: groesse, colorScheme: schema === 'dunkel' ? 'dark' : 'light', deviceScaleFactor: 2, }) const seite = await kontext.newPage() await seite.clock.setFixedTime(FESTE_ZEIT) for (const aufnahme of AUFNAHMEN) { if (aufnahme.pfad !== '/anmelden') { // Für alles außer der Anmeldeseite braucht es eine Sitzung. if ( !(await seite.context().cookies()).some((k) => k.name.includes('session')) ) { await anmelden(seite) } } await seite.goto(aufnahme.pfad) await seite.waitForLoadState('networkidle') await aufnahme.vorbereiten?.(seite) // Der Farbschema-Umschalter und Schriften sollen fertig sein. await seite.waitForTimeout(300) const ziel = `${ZIEL}/${aufnahme.name}-${schema}-${geraet}.png` if (aufnahme.ausschnitt) { await seite.locator(aufnahme.ausschnitt).screenshot({ path: ziel }) } else { await seite.screenshot({ path: ziel, fullPage: true }) } } await kontext.close() }) } }