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, SEED_TAG } from "./helfer";
|
||||
|
||||
/**
|
||||
* Der Weg vom Aufkleber zur Arbeit (#014).
|
||||
@@ -9,19 +10,17 @@ import { prisma } from "@/lib/db";
|
||||
* tun ist, loslegen. Geprueft wird er am **gebauten** Stand, weil genau hier die
|
||||
* Teile zusammenkommen, die einzeln schon funktionierten — die Weiche unter
|
||||
* `/t/<code>`, das Registrieren, die Geraeteseite und der Lauf.
|
||||
*
|
||||
* Voraussetzungen prueft `tests/e2e/global-setup.ts`. Das Beispielgeraet wird
|
||||
* ueber `SEED_TAG` gesucht und nicht ueber den Hostnamen „PC-001“: im Modus
|
||||
* DIENSTLEISTUNG traegt der Name das Kundenkuerzel, und in einer benutzten
|
||||
* Datenbank gibt es „PC-001“ mehr als einmal (#018).
|
||||
*/
|
||||
|
||||
const STEMPEL = Date.now();
|
||||
|
||||
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"]')]);
|
||||
}
|
||||
/** Praefix der Geraete, die dieser Ablauf anlegt – und nur dieser. */
|
||||
const HOSTNAME_PRAEFIX = "ZZ-E2E-TAG-";
|
||||
|
||||
/**
|
||||
* Eine schlichte Vorlage **ohne** Pflichtangaben.
|
||||
@@ -59,7 +58,18 @@ async function tagAnlegen(): Promise<string> {
|
||||
where: { rolle: "ADMIN" },
|
||||
select: { id: true, rolle: true },
|
||||
});
|
||||
const stapel = await tagsErzeugen(1, null, { id: admin.id, rolle: admin.rolle });
|
||||
/*
|
||||
* Der Kunde muss mit: im Modus DIENSTLEISTUNG verlangt `kundeErmitteln` eine
|
||||
* Wahl und wirft sonst „Im Modus Dienstleistung muss ein Kunde gewählt
|
||||
* werden“. Genommen wird der Kunde des Beispielgeraets — an ihm haengt auch
|
||||
* die Geraeteseite, die dieser Ablauf danach oeffnet. Im Modus INTERN wird die
|
||||
* Kennung verworfen, die Angabe schadet dort also nicht (#008).
|
||||
*/
|
||||
const beispiel = await prisma.geraet.findUniqueOrThrow({
|
||||
where: { tagCode: SEED_TAG },
|
||||
select: { kundeId: true },
|
||||
});
|
||||
const stapel = await tagsErzeugen(1, beispiel.kundeId, { id: admin.id, rolle: admin.rolle });
|
||||
const code = stapel.tagCodes[0];
|
||||
if (!code) throw new Error("Der Stapel kam leer zurück.");
|
||||
eigeneTags.push(code);
|
||||
@@ -82,13 +92,13 @@ test.describe("Vom Aufkleber zur Arbeit", () => {
|
||||
* muss er auf **der Geräteseite** stehen und nicht auf der Übersicht — sonst
|
||||
* sucht er das Gerät noch einmal, das er gerade in der Hand hält.
|
||||
*/
|
||||
const geraet = await prisma.geraet.findFirstOrThrow({
|
||||
where: { hostname: "PC-001" },
|
||||
select: { id: true, tagCode: true },
|
||||
const geraet = await prisma.geraet.findUniqueOrThrow({
|
||||
where: { tagCode: SEED_TAG },
|
||||
select: { id: true, hostname: true },
|
||||
});
|
||||
|
||||
await page.context().clearCookies();
|
||||
await page.goto(`/t/${geraet.tagCode}`);
|
||||
await page.goto(`/t/${SEED_TAG}`);
|
||||
await page.waitForURL(/\/anmelden\?ziel=/);
|
||||
|
||||
const email = process.env["SEED_ADMIN_EMAIL"];
|
||||
@@ -99,7 +109,8 @@ test.describe("Vom Aufkleber zur Arbeit", () => {
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
await page.waitForURL(`**/geraete/${geraet.id}`);
|
||||
await expect(page.getByRole("heading", { name: "PC-001" })).toBeVisible();
|
||||
// Der Name kommt aus der Datenbank: er heisst nicht in jedem Modus „PC-001“.
|
||||
await expect(page.getByRole("heading", { name: geraet.hostname ?? SEED_TAG })).toBeVisible();
|
||||
});
|
||||
|
||||
test("registriert einen vorgedruckten Tag und arbeitet daran weiter", async ({ page }) => {
|
||||
@@ -111,7 +122,7 @@ test.describe("Vom Aufkleber zur Arbeit", () => {
|
||||
await page.goto(`/t/${code.toLowerCase()}`);
|
||||
await expect(page.getByRole("heading", { name: "Gerät registrieren" })).toBeVisible();
|
||||
|
||||
const hostname = `ZZ-E2E-${STEMPEL}`;
|
||||
const hostname = `${HOSTNAME_PRAEFIX}${STEMPEL}`;
|
||||
await page.getByLabel("Hostname").fill(hostname);
|
||||
await page.getByLabel("Typ").selectOption("NOTEBOOK");
|
||||
await page.getByRole("button", { name: "Gerät registrieren" }).click();
|
||||
@@ -156,9 +167,15 @@ test.describe("Vom Aufkleber zur Arbeit", () => {
|
||||
|
||||
test("trägt am Handy ohne horizontales Scrollen", async ({ page, isMobile }) => {
|
||||
test.skip(!isMobile, "Nur im Projekt „handy“.");
|
||||
/*
|
||||
* Gesucht wird ueber den Tag-Code und nicht ueber „NB-001“: der Name war eine
|
||||
* Annahme ueber den Beispielbestand, und in einer benutzten Datenbank fuehrt
|
||||
* er auf mehr als ein Geraet. Der Code ist eindeutig — die Liste zeigt danach
|
||||
* genau eine Zeile, und der Weg ueber die Liste bleibt der des Technikers.
|
||||
*/
|
||||
await anmelden(page);
|
||||
await page.goto("/geraete");
|
||||
await page.getByRole("link", { name: "NB-001" }).first().click();
|
||||
await page.goto(`/geraete?suche=${SEED_TAG}`);
|
||||
await page.locator("ul > li").filter({ hasText: SEED_TAG }).getByRole("link").first().click();
|
||||
await page.waitForURL(/\/geraete\/[^/]+$/);
|
||||
|
||||
const masse = await page.evaluate(() => ({
|
||||
@@ -186,7 +203,12 @@ test.afterAll(async () => {
|
||||
* Entwicklungsdatenbank ist das derselbe Bestand.
|
||||
*/
|
||||
const geraete = await prisma.geraet.findMany({
|
||||
where: { OR: [{ hostname: { startsWith: "ZZ-E2E-" } }, { tagCode: { in: eigeneTags } }] },
|
||||
/*
|
||||
* Der Praefix gehoert dieser Datei allein. Vorher stand hier `ZZ-E2E-`, und
|
||||
* damit raeumte dieser Nachlauf auch die Geraete aus
|
||||
* `tests/e2e/geraete.spec.ts` weg — fremde Daten, wenn auch Testdaten (#018).
|
||||
*/
|
||||
where: { OR: [{ hostname: { startsWith: HOSTNAME_PRAEFIX } }, { tagCode: { in: eigeneTags } }] },
|
||||
select: { id: true },
|
||||
});
|
||||
const kennungen = geraete.map((geraet) => geraet.id);
|
||||
|
||||
Reference in New Issue
Block a user