feat(doku): Anleitung, PDF und Ende-zu-Ende-Abnahme (#36)
This commit was merged in pull request #36.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { expect, test, type Page } from "@playwright/test";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import "dotenv/config";
|
||||
import { prisma } from "@/lib/db";
|
||||
import { anmelden } from "./helfer";
|
||||
|
||||
/**
|
||||
* Uebersicht und Druckansicht am gebauten Stand (#015).
|
||||
@@ -9,17 +10,22 @@ import { prisma } from "@/lib/db";
|
||||
* Dringlichkeit, die Druckansicht gehoert auf Papier. Was davon stimmt, zeigt
|
||||
* erst der Browser — die Lesemodelle dahinter pruefen `tests/uebersicht.test.ts`
|
||||
* und `tests/druckansicht.test.ts`.
|
||||
*
|
||||
* Voraussetzungen prueft `tests/e2e/global-setup.ts`. Jeden Lauf, den diese
|
||||
* Ablaeufe brauchen, legen sie selbst an und raeumen ihn hinterher weg. Vorher
|
||||
* holten sie sich mit `findFirstOrThrow` irgendeinen vorhandenen Lauf und
|
||||
* erwarteten, dass „Zuletzt bearbeitet“ gefuellt ist — gegen eine frische
|
||||
* Datenbank scheiterte beides, das eine mit „No record was found“, das andere
|
||||
* mit einem Zeitablauf auf einen Verweis, den es nicht gab (#018).
|
||||
*/
|
||||
|
||||
async function anmelden(seite: Page) {
|
||||
const email = process.env["SEED_ADMIN_EMAIL"];
|
||||
const passwort = process.env["SEED_ADMIN_PASSWORD"];
|
||||
if (!email || !passwort) throw new Error("SEED_ADMIN_EMAIL und SEED_ADMIN_PASSWORD fehlen.");
|
||||
await seite.goto("/anmelden");
|
||||
await seite.fill('input[name="email"]', email);
|
||||
await seite.fill('input[name="passwort"]', passwort);
|
||||
await Promise.all([seite.waitForURL("**/"), seite.click('button[type="submit"]')]);
|
||||
}
|
||||
const STEMPEL = Date.now();
|
||||
|
||||
/** Fortlaufend, damit die Laeufe eines Durchgangs sich nicht verwechseln. */
|
||||
let laufende = 0;
|
||||
|
||||
/** Name und Titel tragen diesen Praefix – nur daran raeumt der Nachlauf auf. */
|
||||
const PRAEFIX = "ZZ E2E Druck";
|
||||
|
||||
/**
|
||||
* Ein Lauf aus einer Vorlage, die `{{generiertes_passwort}}` wirklich enthaelt.
|
||||
@@ -27,12 +33,16 @@ async function anmelden(seite: Page) {
|
||||
* Direkt ueber Prisma: geprueft werden soll die **Druckansicht**, nicht der Weg
|
||||
* zum Lauf — den prueft `tests/e2e/laeufe.spec.ts` vom Anlegen bis zum Archiv.
|
||||
*/
|
||||
async function laufMitPasswortschritt(): Promise<string> {
|
||||
const stempel = Date.now();
|
||||
const kunde = await prisma.kunde.findFirstOrThrow({ select: { id: true } });
|
||||
const vorlage = await prisma.vorlage.create({
|
||||
data: { name: `ZZ E2E Druck ${stempel}`, kategorie: "ZZ Test" },
|
||||
async function laufMitPasswortschritt(): Promise<{ id: string; titel: string }> {
|
||||
laufende += 1;
|
||||
const marke = `${PRAEFIX} ${STEMPEL}-${laufende}`;
|
||||
// Ueber `istEigeneOrganisation` und nicht ueber den ersten Treffer: im Modus
|
||||
// DIENSTLEISTUNG waere das ein beliebiger Demo-Kunde.
|
||||
const kunde = await prisma.kunde.findFirstOrThrow({
|
||||
where: { istEigeneOrganisation: true },
|
||||
select: { id: true },
|
||||
});
|
||||
const vorlage = await prisma.vorlage.create({ data: { name: marke, kategorie: "ZZ Test" } });
|
||||
const version = await prisma.vorlagenVersion.create({
|
||||
data: { vorlageId: vorlage.id, version: 1, status: "ENTWURF" },
|
||||
});
|
||||
@@ -53,9 +63,9 @@ async function laufMitPasswortschritt(): Promise<string> {
|
||||
});
|
||||
|
||||
const lauf = await prisma.lauf.create({
|
||||
data: { vorlagenVersionId: version.id, kundeId: kunde.id, titel: `ZZ E2E Druck ${stempel}` },
|
||||
data: { vorlagenVersionId: version.id, kundeId: kunde.id, titel: marke },
|
||||
});
|
||||
return lauf.id;
|
||||
return { id: lauf.id, titel: marke };
|
||||
}
|
||||
|
||||
test.describe("Übersicht", () => {
|
||||
@@ -66,12 +76,19 @@ test.describe("Übersicht", () => {
|
||||
});
|
||||
|
||||
test("führt von einer Zeile in den Lauf", async ({ page }) => {
|
||||
/*
|
||||
* Der Ablauf bringt die Zeile mit, auf die er klickt. „Zuletzt bearbeitet“
|
||||
* sortiert nach `geaendertAm` absteigend, der eben angelegte Lauf steht also
|
||||
* oben — und weil der Klick auf **seinen** Titel geht, prueft der Test einen
|
||||
* Weg und nicht die Datenlage.
|
||||
*/
|
||||
const lauf = await laufMitPasswortschritt();
|
||||
await anmelden(page);
|
||||
const zuletzt = page
|
||||
.locator("section")
|
||||
.filter({ has: page.getByRole("heading", { name: "Zuletzt bearbeitet" }) });
|
||||
await zuletzt.getByRole("link").first().click();
|
||||
await page.waitForURL(/\/laeufe\/[^/]+$/);
|
||||
await zuletzt.getByRole("link", { name: new RegExp(lauf.titel) }).click();
|
||||
await page.waitForURL(`**/laeufe/${lauf.id}`);
|
||||
});
|
||||
|
||||
test("trägt am Handy ohne horizontales Scrollen", async ({ page, isMobile }) => {
|
||||
@@ -88,8 +105,10 @@ test.describe("Übersicht", () => {
|
||||
test.describe("Druckansicht", () => {
|
||||
test("ist hell, ohne Navigation und passt auf A4", async ({ page }) => {
|
||||
test.skip(test.info().project.name !== "desktop", "Das Seitenformat hängt nicht am Gerät.");
|
||||
// Der eigene Lauf statt `findFirstOrThrow`: gegen eine frische Datenbank gab
|
||||
// es keinen, und die Meldung sprach von „No record was found“ (#018).
|
||||
const lauf = await laufMitPasswortschritt();
|
||||
await anmelden(page);
|
||||
const lauf = await prisma.lauf.findFirstOrThrow({ select: { id: true } });
|
||||
await page.goto(`/drucken/lauf/${lauf.id}`);
|
||||
|
||||
// Keine Hülle: weder Seitenleiste noch der Scannen-Knopf gehören aufs Blatt.
|
||||
@@ -123,9 +142,9 @@ test.describe("Druckansicht", () => {
|
||||
* dann bestanden, wenn die Druckansicht Passwörter erzeugte (Reviewbefund
|
||||
* zu #015).
|
||||
*/
|
||||
const laufId = await laufMitPasswortschritt();
|
||||
const lauf = await laufMitPasswortschritt();
|
||||
await anmelden(page);
|
||||
await page.goto(`/laeufe/${laufId}`);
|
||||
await page.goto(`/laeufe/${lauf.id}`);
|
||||
await page.getByRole("link", { name: "Drucken" }).click();
|
||||
await page.waitForURL(/\/drucken\/lauf\//);
|
||||
|
||||
@@ -146,7 +165,7 @@ test.describe("Druckansicht", () => {
|
||||
|
||||
test.afterAll(async () => {
|
||||
const laeufe = await prisma.lauf.findMany({
|
||||
where: { titel: { startsWith: "ZZ E2E Druck" } },
|
||||
where: { titel: { startsWith: PRAEFIX } },
|
||||
select: { id: true },
|
||||
});
|
||||
const kennungen = laeufe.map((lauf) => lauf.id);
|
||||
@@ -157,6 +176,7 @@ test.afterAll(async () => {
|
||||
});
|
||||
await prisma.lauf.deleteMany({ where: { id: { in: kennungen } } });
|
||||
}
|
||||
await prisma.vorlage.deleteMany({ where: { name: { startsWith: "ZZ E2E Druck" } } });
|
||||
// Die Vorlagen zuletzt: an ihnen hingen gerade noch die Laeufe.
|
||||
await prisma.vorlage.deleteMany({ where: { name: { startsWith: PRAEFIX } } });
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user