chore: Screenshot-Kette und Demo-Seed
npm run screenshots startet eine Wegwerf-Instanz in einem eigenen Compose-Projekt mit eigener Datenbank, spielt ausschließlich erfundene Daten ein, fährt die Seiten mit Playwright ab und räumt am Ende alles wieder weg. Je Seite entstehen vier Bilder: hell und dunkel, Schreibtisch und Handy. Die Uhr steht fest, damit sich zwischen zwei Läufen nur das ändert, was sich wirklich geändert hat. Der Demo-Seed verweigert den Dienst ohne DEMO_MODUS=true — er würde sonst erfundene Daten in eine echte Datenbank schreiben. Test- und Werkzeugordner sind jetzt aus dem Docker-Kontext ausgenommen. Ein Typfehler in scripts/screenshots.ts hatte den Bau des Abbilds blockiert, obwohl die Datei dort nichts zu suchen hat. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
e3390c88f4
commit
a88273117c
@@ -0,0 +1,88 @@
|
||||
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<void>
|
||||
}
|
||||
|
||||
const AUFNAHMEN: Aufnahme[] = [
|
||||
{ name: 'anmelden', pfad: '/anmelden' },
|
||||
{ name: 'start', pfad: '/' },
|
||||
{ name: 'bereiche', pfad: '/bereiche' },
|
||||
{ name: 'einstellungen', pfad: '/einstellungen' },
|
||||
{ name: 'protokoll', pfad: '/verwaltung/protokoll' },
|
||||
]
|
||||
|
||||
async function anmelden(seite: Page): Promise<void> {
|
||||
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)
|
||||
|
||||
await seite.screenshot({
|
||||
path: `${ZIEL}/${aufnahme.name}-${schema}-${geraet}.png`,
|
||||
fullPage: true,
|
||||
})
|
||||
}
|
||||
|
||||
await kontext.close()
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user