chore(hosts): Demo-Daten, Screenshots und Issue-Notizen (#008)

SSHKV_SEED_DEMO=1 legt sechs Demo-Hosts, drei Gruppen und einen Kunden an,
damit Entwicklung, Screenshots und Handbuch ohne echte Server auskommen.
Nur mit der Variable, damit eine echte Instanz nie Phantom-Hosts bekommt;
Upsert nach Name haelt den Seed idempotent.

Das Screenshot-Skript kennt jetzt Seiten mit wechselnder ID (folgen: erster
passender Link) und nimmt Hostliste und Hostdetail auf.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-12 09:50:53 +02:00
co-authored by Claude Opus 5.5
parent 90a41dc55d
commit c8a415f1ca
7 changed files with 140 additions and 11 deletions
+18 -3
View File
@@ -19,11 +19,17 @@ import { chromium } from "@playwright/test";
const BASIS = (process.env["SSHKV_URL"] ?? "http://localhost:3400").replace(/\/$/, "");
const ZIEL = process.env["SSHKV_BILDER"] ?? join(process.cwd(), "docs/anleitung/bilder");
/** `oeffentlich`: ohne Anmeldung aufnehmen. Alle anderen nach Anmeldung ueber den Mock-OIDC (#004). */
const SEITEN: { name: string; pfad: string; oeffentlich?: boolean }[] = [
/**
* `oeffentlich`: ohne Anmeldung aufnehmen. Alle anderen nach Anmeldung ueber den Mock-OIDC (#004).
* `folgen`: Seiten mit wechselnder ID (#008) – erst `pfad` laden, dann dem ersten Link folgen,
* der zum Selektor passt (z. B. der erste Host der Liste, bei SSHKV_SEED_DEMO=1 ein Demo-Host).
*/
const SEITEN: { name: string; pfad: string; oeffentlich?: boolean; folgen?: string }[] = [
{ name: "anmelden", pfad: "/anmelden", oeffentlich: true },
{ name: "uebersicht", pfad: "/" },
{ name: "schluessel-detail", pfad: "/schluessel/beispiel" },
{ name: "hosts", pfad: "/hosts" },
{ name: "host-detail", pfad: "/hosts", folgen: 'main table a[href^="/hosts/"]' },
];
const ANSICHTEN = [
@@ -62,7 +68,16 @@ async function main() {
await seite.waitForURL(`${BASIS}/`);
angemeldet = true;
}
const antwort = await seite.goto(`${BASIS}${s.pfad}`, { waitUntil: "networkidle" });
let antwort = await seite.goto(`${BASIS}${s.pfad}`, { waitUntil: "networkidle" });
if (s.folgen && antwort?.ok()) {
const links = seite.locator(s.folgen);
const ziel = (await links.count()) > 0 ? await links.first().getAttribute("href") : null;
if (!ziel) {
fehler.push(`${s.pfad}: kein Link für „${s.name}“ (${s.folgen}) – Demo-Daten geseedet?`);
continue;
}
antwort = await seite.goto(`${BASIS}${ziel}`, { waitUntil: "networkidle" });
}
if (!antwort?.ok()) {
fehler.push(`${s.pfad}: HTTP ${antwort?.status() ?? "keine Antwort"}`);
continue;