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>
143 lines
3.8 KiB
TypeScript
143 lines
3.8 KiB
TypeScript
/**
|
|
* Nimmt die Bilder für das Handbuch auf.
|
|
*
|
|
* 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 — auch wenn unterwegs etwas
|
|
* schiefgeht.
|
|
*
|
|
* An eine Instanz mit echten Daten kommt dieser Ablauf nicht heran: die
|
|
* Datenbank entsteht neu, wird nur über ihren eigenen Port angesprochen und
|
|
* samt Volume wieder entfernt.
|
|
*
|
|
* Aufruf: npm run screenshots
|
|
*/
|
|
import { spawnSync } from 'node:child_process'
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
const WURZEL = fileURLToPath(new URL('..', import.meta.url))
|
|
const PROJEKT = 'planer-screenshots'
|
|
const COMPOSE_DATEI = 'docker-compose.screenshots.yml'
|
|
|
|
const APP_PORT = process.env.SCREENSHOT_APP_PORT ?? '3200'
|
|
const DB_PORT = process.env.SCREENSHOT_DB_PORT ?? '5455'
|
|
|
|
const UMGEBUNG = {
|
|
...process.env,
|
|
SCREENSHOT_APP_PORT: APP_PORT,
|
|
SCREENSHOT_DB_PORT: DB_PORT,
|
|
}
|
|
|
|
function meldung(text: string): void {
|
|
console.log(`▸ ${text}`)
|
|
}
|
|
|
|
function laufen(
|
|
befehl: string,
|
|
argumente: string[],
|
|
zusatz: Record<string, string> = {},
|
|
): number {
|
|
const ergebnis = spawnSync(befehl, argumente, {
|
|
cwd: WURZEL,
|
|
stdio: 'inherit',
|
|
env: { ...UMGEBUNG, ...zusatz },
|
|
})
|
|
return ergebnis.status ?? 1
|
|
}
|
|
|
|
function compose(argumente: string[]): number {
|
|
return laufen('docker', ['compose', '-p', PROJEKT, '-f', COMPOSE_DATEI, ...argumente])
|
|
}
|
|
|
|
function node(skript: string, zusatz: Record<string, string>): number {
|
|
return laufen(
|
|
process.execPath,
|
|
[`${WURZEL}node_modules/tsx/dist/cli.mjs`, skript],
|
|
zusatz,
|
|
)
|
|
}
|
|
|
|
async function wartenAufGesundheit(sekunden: number): Promise<boolean> {
|
|
const ziel = `http://127.0.0.1:${APP_PORT}/api/health`
|
|
const frist = Date.now() + sekunden * 1000
|
|
|
|
while (Date.now() < frist) {
|
|
try {
|
|
const antwort = await fetch(ziel)
|
|
if (antwort.ok) {
|
|
const inhalt = (await antwort.json()) as { status?: string }
|
|
if (inhalt.status === 'ok') return true
|
|
}
|
|
} catch {
|
|
// Noch nicht da, gleich noch einmal.
|
|
}
|
|
await new Promise((weiter) => setTimeout(weiter, 2000))
|
|
}
|
|
return false
|
|
}
|
|
|
|
function aufraeumen(): void {
|
|
meldung('Wegwerf-Instanz entfernen.')
|
|
compose(['down', '-v', '--remove-orphans'])
|
|
}
|
|
|
|
async function main(): Promise<number> {
|
|
if (laufen('docker', ['info']) !== 0) {
|
|
console.error('Der Docker-Daemon läuft nicht.')
|
|
return 1
|
|
}
|
|
|
|
// Reste eines abgebrochenen Laufs zuerst wegräumen.
|
|
compose(['down', '-v', '--remove-orphans'])
|
|
|
|
meldung(`Wegwerf-Instanz bauen und starten (App auf ${APP_PORT}, DB auf ${DB_PORT}).`)
|
|
if (compose(['up', '-d', '--build']) !== 0) {
|
|
console.error('Die Wegwerf-Instanz ließ sich nicht starten.')
|
|
return 1
|
|
}
|
|
|
|
meldung('Auf die Anwendung warten.')
|
|
if (!(await wartenAufGesundheit(180))) {
|
|
console.error('Die Anwendung ist nicht gesund geworden.')
|
|
compose(['logs', '--tail', '50', 'app'])
|
|
return 1
|
|
}
|
|
|
|
meldung('Erfundene Daten einspielen.')
|
|
const demoUrl = `postgresql://demo:demo@127.0.0.1:${DB_PORT}/demo?schema=public`
|
|
if (node('prisma/demo-seed.ts', { DATABASE_URL: demoUrl, DEMO_MODUS: 'true' }) !== 0) {
|
|
console.error('Der Demo-Seed ist fehlgeschlagen.')
|
|
return 1
|
|
}
|
|
|
|
meldung('Bilder aufnehmen.')
|
|
const playwright = laufen(
|
|
process.execPath,
|
|
[
|
|
`${WURZEL}node_modules/@playwright/test/cli.js`,
|
|
'test',
|
|
'--config',
|
|
'playwright.screenshots.config.ts',
|
|
],
|
|
{ SCREENSHOT_APP_PORT: APP_PORT },
|
|
)
|
|
if (playwright !== 0) {
|
|
console.error('Die Aufnahme ist fehlgeschlagen.')
|
|
return 1
|
|
}
|
|
|
|
meldung('Fertig. Die Bilder liegen in docs/bilder/.')
|
|
return 0
|
|
}
|
|
|
|
let code = 1
|
|
try {
|
|
code = await main()
|
|
} catch (fehler) {
|
|
console.error('Der Screenshot-Lauf ist abgebrochen:', fehler)
|
|
} finally {
|
|
aufraeumen()
|
|
}
|
|
|
|
process.exit(code)
|