Screenshots per scripts/screenshots.ts aus dem gebauten Stand. Dabei gefunden und gefüllt: die Übersicht zeigte nur einen Platzhalter statt der letzten Deployments. Closes #018 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
92 lines
3.6 KiB
TypeScript
92 lines
3.6 KiB
TypeScript
/**
|
||
* Screenshots für das README aus dem gebauten Stand (`scripts/neu-starten.sh`, Port 3310), dunkles
|
||
* Theme, 1440 px und 390 px. Ergebnis: docs/bilder/*.png
|
||
*
|
||
* pnpm exec tsx scripts/screenshots.ts [auftrag-kurzid]
|
||
*/
|
||
import { mkdirSync } from "node:fs";
|
||
import { chromium, type Page } from "@playwright/test";
|
||
|
||
const BASIS = process.env["SCREENSHOT_URL"] ?? "http://127.0.0.1:3310";
|
||
const BENUTZER = process.env["E2E_BENUTZER"] ?? "admin";
|
||
const PASSWORT = process.env["E2E_PASSWORT"] ?? "proxdeploy-dev-admin";
|
||
const ZIEL = "docs/bilder";
|
||
|
||
async function anmelden(seite: Page) {
|
||
await seite.goto(`${BASIS}/anmelden`);
|
||
await seite.getByLabel("Benutzername").fill(BENUTZER);
|
||
await seite.getByLabel("Passwort").fill(PASSWORT);
|
||
await seite.getByRole("button", { name: "Anmelden" }).click();
|
||
await seite.waitForURL((url) => !url.pathname.startsWith("/anmelden"));
|
||
}
|
||
|
||
async function bild(seite: Page, name: string, ganz = false) {
|
||
await seite.waitForLoadState("networkidle");
|
||
// Blinkender Cursor und Spinner sollen nicht zufällig halb im Bild stehen.
|
||
await seite.addStyleTag({ content: "*{animation:none!important;transition:none!important}" });
|
||
await seite.screenshot({ path: `${ZIEL}/${name}.png`, fullPage: ganz });
|
||
console.log(`${ZIEL}/${name}.png`);
|
||
}
|
||
|
||
async function main() {
|
||
const auftrag = process.argv[2];
|
||
if (!auftrag) throw new Error("Kurz-ID eines erfolgreichen Auftrags angeben (für die Live-Ansicht).");
|
||
mkdirSync(ZIEL, { recursive: true });
|
||
const browser = await chromium.launch();
|
||
try {
|
||
const kontext = await browser.newContext({
|
||
viewport: { width: 1440, height: 900 },
|
||
deviceScaleFactor: 1,
|
||
});
|
||
await kontext.addCookies([{ name: "pd_theme", value: "dunkel", url: BASIS }]);
|
||
const seite = await kontext.newPage();
|
||
await anmelden(seite);
|
||
|
||
await seite.goto(`${BASIS}/`);
|
||
await bild(seite, "uebersicht");
|
||
|
||
await seite.goto(`${BASIS}/auftraege/${auftrag}`);
|
||
await bild(seite, "live-ansicht");
|
||
|
||
await seite.goto(`${BASIS}/auftraege`);
|
||
await bild(seite, "verlauf");
|
||
|
||
await seite.goto(`${BASIS}/server/demo`);
|
||
await bild(seite, "server", true);
|
||
|
||
await seite.goto(`${BASIS}/katalog`);
|
||
await bild(seite, "katalog");
|
||
|
||
// Assistent bis zur Zusammenfassung – mit echtem Dry-Run gegen den Server.
|
||
await seite.goto(`${BASIS}/ausrollen`);
|
||
await seite.waitForLoadState("networkidle");
|
||
const weiter = async (bis: number) => {
|
||
await seite.getByRole("button", { name: "Weiter" }).click();
|
||
await seite.getByText(`Schritt ${bis} von 9`).waitFor();
|
||
};
|
||
for (let s = 2; s <= 4; s++) await weiter(s);
|
||
await seite.getByLabel("Name (Hostname)").fill("web01");
|
||
for (let s = 5; s <= 7; s++) await weiter(s);
|
||
// Ohne hinterlegten Schlüssel einen angeben (öffentlicher Beispielschlüssel).
|
||
const feld = seite.locator("textarea#schluessel");
|
||
if ((await feld.inputValue()) === "")
|
||
await feld.fill(
|
||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEFTdkCuqQ6mF7I8QzmkNaQpKj7S/I2+yuxWeYasJjLd florian@laptop",
|
||
);
|
||
for (let s = 8; s <= 9; s++) await weiter(s);
|
||
await seite.getByText("Geplante Proxmox-Aufrufe").waitFor({ timeout: 60_000 });
|
||
await bild(seite, "assistent-zusammenfassung");
|
||
|
||
const handy = await browser.newContext({ viewport: { width: 390, height: 844 }, deviceScaleFactor: 2 });
|
||
await handy.addCookies([{ name: "pd_theme", value: "dunkel", url: BASIS }]);
|
||
const klein = await handy.newPage();
|
||
await anmelden(klein);
|
||
await klein.goto(`${BASIS}/auftraege/${auftrag}`);
|
||
await bild(klein, "handy-live-ansicht");
|
||
} finally {
|
||
await browser.close();
|
||
}
|
||
}
|
||
|
||
await main();
|