Phase 10: Mandantenfähigkeit (#15)
This commit was merged in pull request #15.
This commit is contained in:
@@ -0,0 +1,241 @@
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { ADMIN_EMAIL, ADMIN_PASSWORT, anmelden } from "./wehr";
|
||||
|
||||
/**
|
||||
* E2E-Tests für Phase 10 — Mandantenfähigkeit.
|
||||
*
|
||||
* Geprüft wird das, wovon die Trennung abhängt:
|
||||
*
|
||||
* * wer nur zu einer Wehr gehört, sieht keinen Wähler
|
||||
* * wer zu mehreren gehört, landet in seiner eigenen und kann wechseln
|
||||
* * nach dem Wechsel stehen die Daten der anderen Wehr da, nicht die alten
|
||||
* * als Kreisaufsicht steht der Hinweis, und es gibt nichts zu ändern
|
||||
* * die Kasse der betreuten Wehr bleibt zu
|
||||
*
|
||||
* Voraussetzung: `npm run db:test-reset`. Der Seed legt dabei die Testwehr,
|
||||
* eine Nachbarwehr und ein Konto an, das in der einen Mitglied und in der
|
||||
* anderen Aufsicht ist.
|
||||
*/
|
||||
test.describe.configure({ mode: "serial" });
|
||||
|
||||
/** Das Konto der Kreisebene — Mitglied hier, Aufsicht nebenan. */
|
||||
const KBI_EMAIL = process.env.E2E_KBI_EMAIL ?? "kbi@ff-teststelle.de";
|
||||
const KBI_PASSWORT = process.env.E2E_KBI_PASSWORT ?? "Feuerwehr2026";
|
||||
|
||||
/**
|
||||
* Öffnet die Seitenleiste, falls sie hinter dem Menüknopf steckt.
|
||||
*
|
||||
* Auf dem Tablet (Galaxy Tab S4 quer, 1138 px) liegt die Leiste unterhalb der
|
||||
* `md`-Grenze und ist eingeklappt. Der Wehrwähler sitzt darin — wer ihn dort
|
||||
* sucht, ohne vorher aufzuklappen, wartet vergeblich.
|
||||
*/
|
||||
async function seitenleisteOeffnen(page: import("@playwright/test").Page) {
|
||||
const knopf = page.getByRole("button", { name: "Navigation öffnen" });
|
||||
if (await knopf.isVisible()) await knopf.click();
|
||||
}
|
||||
|
||||
/** Meldet ein beliebiges Konto an. */
|
||||
async function anmeldenAls(page: import("@playwright/test").Page, email: string, passwort: string) {
|
||||
await page.goto("/anmelden");
|
||||
await page.getByLabel("E-Mail-Adresse").fill(email);
|
||||
await page.getByLabel("Passwort").fill(passwort);
|
||||
await page.getByRole("button", { name: "Anmelden" }).click();
|
||||
await expect(page, `Anmeldung als ${email} fehlgeschlagen.`).toHaveURL("/");
|
||||
}
|
||||
|
||||
test.describe("Ein Konto, eine Wehr", () => {
|
||||
test("zeigt keinen Wehrwähler, wenn es nichts zu wählen gibt", async ({ page }) => {
|
||||
await anmelden(page);
|
||||
|
||||
// Der Name der Wehr steht da — aber nicht als Auswahl. Ein Auswahlfeld mit
|
||||
// genau einem Eintrag ist eine Frage ohne Antwortmöglichkeit.
|
||||
await expect(page.getByRole("button", { name: /Wehr wechseln/ })).toHaveCount(0);
|
||||
await expect(page.getByRole("listbox", { name: "Wehr wechseln" })).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("sieht keinen Aufsichtshinweis", async ({ page }) => {
|
||||
await anmelden(page);
|
||||
await expect(page.getByText("Sie sehen diese Wehr als")).toHaveCount(0);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Ein Konto, zwei Wehren", () => {
|
||||
test("landet nach der Anmeldung in der eigenen Wehr, nicht in der betreuten", async ({
|
||||
page,
|
||||
}) => {
|
||||
await anmeldenAls(page, KBI_EMAIL, KBI_PASSWORT);
|
||||
|
||||
// Die eigene vor der betreuten: wer eine Wehr führt und eine zweite
|
||||
// beaufsichtigt, will in seiner landen.
|
||||
await expect(page.getByText("Sie sehen diese Wehr als")).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("bietet den Wehrwähler an", async ({ page }) => {
|
||||
await anmeldenAls(page, KBI_EMAIL, KBI_PASSWORT);
|
||||
|
||||
await seitenleisteOeffnen(page);
|
||||
await page.getByRole("button", { name: /Wehr wechseln/ }).click();
|
||||
|
||||
const liste = page.getByRole("listbox", { name: "Wehr wechseln" });
|
||||
await expect(liste).toBeVisible();
|
||||
await expect(liste.getByRole("option")).toHaveCount(2);
|
||||
|
||||
// Beide Arten stehen mit Klartext da — nicht nur mit einem Symbol.
|
||||
await expect(liste.getByText("Mitglied", { exact: true })).toBeVisible();
|
||||
await expect(liste.getByText("Aufsicht — nur lesen")).toBeVisible();
|
||||
});
|
||||
|
||||
test("wechselt in die betreute Wehr und sagt, dass dort nichts geht", async ({ page }) => {
|
||||
await anmeldenAls(page, KBI_EMAIL, KBI_PASSWORT);
|
||||
|
||||
await seitenleisteOeffnen(page);
|
||||
await page.getByRole("button", { name: /Wehr wechseln/ }).click();
|
||||
await page
|
||||
.getByRole("listbox", { name: "Wehr wechseln" })
|
||||
.getByRole("option")
|
||||
.filter({ hasText: "Aufsicht" })
|
||||
.click();
|
||||
|
||||
// Der Hinweis steht dauerhaft, nicht als kurz aufblitzende Meldung.
|
||||
await expect(page.getByText("Sie sehen diese Wehr als")).toBeVisible();
|
||||
await expect(page.getByRole("note").filter({ hasText: "Kreisaufsicht" })).toBeVisible();
|
||||
});
|
||||
|
||||
test("zeigt nach dem Wechsel die Mitglieder der anderen Wehr", async ({ page }) => {
|
||||
await anmeldenAls(page, KBI_EMAIL, KBI_PASSWORT);
|
||||
|
||||
await seitenleisteOeffnen(page);
|
||||
await page.getByRole("button", { name: /Wehr wechseln/ }).click();
|
||||
await page
|
||||
.getByRole("listbox", { name: "Wehr wechseln" })
|
||||
.getByRole("option")
|
||||
.filter({ hasText: "Aufsicht" })
|
||||
.click();
|
||||
await expect(page.getByText("Sie sehen diese Wehr als")).toBeVisible();
|
||||
|
||||
await page.goto("/mitglieder");
|
||||
|
||||
// Die drei aus der Nachbarwehr — und nicht die fünfzehn der eigenen.
|
||||
await expect(page.getByRole("cell", { name: /Sailer/ })).toBeVisible();
|
||||
await expect(page.getByRole("cell", { name: /Ostermeier/ })).toBeVisible();
|
||||
|
||||
// Die Kreisaufsicht selbst steht in keiner Mitgliederliste: sie gehört
|
||||
// der Wehr nicht an und hat dort keine Akte.
|
||||
await expect(page.getByRole("cell", { name: /Huber/ })).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("lässt die Kreisaufsicht in der betreuten Wehr nichts anlegen", async ({ page }) => {
|
||||
await anmeldenAls(page, KBI_EMAIL, KBI_PASSWORT);
|
||||
|
||||
await seitenleisteOeffnen(page);
|
||||
await page.getByRole("button", { name: /Wehr wechseln/ }).click();
|
||||
await page
|
||||
.getByRole("listbox", { name: "Wehr wechseln" })
|
||||
.getByRole("option")
|
||||
.filter({ hasText: "Aufsicht" })
|
||||
.click();
|
||||
await expect(page.getByText("Sie sehen diese Wehr als")).toBeVisible();
|
||||
|
||||
await page.goto("/mitglieder");
|
||||
|
||||
// Kein Knopf, der ins Leere führt. Das Recht fehlt serverseitig ohnehin —
|
||||
// die Oberfläche soll es aber gar nicht erst anbieten.
|
||||
await expect(page.getByRole("button", { name: /Mitglied anlegen/ })).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("hält die Kasse der betreuten Wehr geschlossen", async ({ page }) => {
|
||||
await anmeldenAls(page, KBI_EMAIL, KBI_PASSWORT);
|
||||
|
||||
await seitenleisteOeffnen(page);
|
||||
await page.getByRole("button", { name: /Wehr wechseln/ }).click();
|
||||
await page
|
||||
.getByRole("listbox", { name: "Wehr wechseln" })
|
||||
.getByRole("option")
|
||||
.filter({ hasText: "Aufsicht" })
|
||||
.click();
|
||||
await expect(page.getByText("Sie sehen diese Wehr als")).toBeVisible();
|
||||
|
||||
// Sie gehört dem Verein oder der Kommune, nicht der Kreisaufsicht.
|
||||
await seitenleisteOeffnen(page);
|
||||
await expect(page.locator("aside").getByRole("link", { name: "Kasse" })).toHaveCount(0);
|
||||
|
||||
await page.goto("/kasse");
|
||||
await expect(page).not.toHaveURL(/\/kasse$/);
|
||||
});
|
||||
|
||||
test("kommt in die eigene Wehr zurück", async ({ page }) => {
|
||||
await anmeldenAls(page, KBI_EMAIL, KBI_PASSWORT);
|
||||
|
||||
await seitenleisteOeffnen(page);
|
||||
await page.getByRole("button", { name: /Wehr wechseln/ }).click();
|
||||
await page
|
||||
.getByRole("listbox", { name: "Wehr wechseln" })
|
||||
.getByRole("option")
|
||||
.filter({ hasText: "Aufsicht" })
|
||||
.click();
|
||||
await expect(page.getByText("Sie sehen diese Wehr als")).toBeVisible();
|
||||
|
||||
await seitenleisteOeffnen(page);
|
||||
await page.getByRole("button", { name: /Wehr wechseln/ }).click();
|
||||
await page
|
||||
.getByRole("listbox", { name: "Wehr wechseln" })
|
||||
.getByRole("option")
|
||||
.filter({ hasText: "Mitglied" })
|
||||
.click();
|
||||
|
||||
await expect(page.getByText("Sie sehen diese Wehr als")).toHaveCount(0);
|
||||
await seitenleisteOeffnen(page);
|
||||
await expect(page.locator("aside").getByRole("link", { name: "Kasse" })).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Der Administrator", () => {
|
||||
test("bleibt nach der Umstellung anmeldbar", async ({ page }) => {
|
||||
// Die Migration hat sein Konto aus der Personenakte gelöst. Wäre dabei
|
||||
// etwas verlorengegangen, käme er hier nicht mehr hinein — und niemand
|
||||
// sonst auch.
|
||||
await anmeldenAls(page, ADMIN_EMAIL, ADMIN_PASSWORT);
|
||||
await expect(page.getByRole("heading", { level: 1 })).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Wehren und Konten", () => {
|
||||
test("steht nur dem Verwalter offen", async ({ page }) => {
|
||||
// Der KBI führt seine Wehr, verwaltet aber nicht die Installation.
|
||||
await anmeldenAls(page, KBI_EMAIL, KBI_PASSWORT);
|
||||
|
||||
await seitenleisteOeffnen(page);
|
||||
await expect(
|
||||
page.locator("aside").getByRole("link", { name: "Wehren und Konten" }),
|
||||
).toHaveCount(0);
|
||||
|
||||
// Und die Seite selbst schickt ihn weg, nicht nur das Menü.
|
||||
await page.goto("/wehren");
|
||||
await expect(page).not.toHaveURL(/\/wehren$/);
|
||||
});
|
||||
|
||||
test("zeigt dem Verwalter die Wehren dieser Installation", async ({ page }) => {
|
||||
await anmeldenAls(page, ADMIN_EMAIL, ADMIN_PASSWORT);
|
||||
await seitenleisteOeffnen(page);
|
||||
await page.locator("aside").getByRole("link", { name: "Wehren und Konten" }).click();
|
||||
|
||||
await expect(page.getByRole("heading", { name: "Wehren und Konten", level: 1 })).toBeVisible();
|
||||
|
||||
// Die Testwehr und ihre Nachbarwehr aus dem Seed. Der Verwalter sieht
|
||||
// bewusst **alle** Wehren der Installation — auch die einer anderen
|
||||
// Kommune, wenn sie auf demselben Server liegt. Das ist der Unterschied
|
||||
// zwischen dem Betreiber und einer Wehr.
|
||||
await expect(page.getByRole("heading", { name: "FF Teststelle Nachbar" })).toBeVisible();
|
||||
await expect(page.getByRole("heading", { name: "FF Teststelle", exact: true })).toBeVisible();
|
||||
});
|
||||
|
||||
test("zeigt, welches Konto zu welchen Wehren gehört", async ({ page }) => {
|
||||
await anmeldenAls(page, ADMIN_EMAIL, ADMIN_PASSWORT);
|
||||
await page.goto("/wehren");
|
||||
|
||||
// Das Konto der Kreisebene steht mit beiden Zuordnungen da — und die
|
||||
// Aufsicht ist als solche gekennzeichnet, nicht als Mitgliedschaft.
|
||||
await expect(page.getByText(KBI_EMAIL)).toBeVisible();
|
||||
await expect(page.getByText("Kreisaufsicht — nur lesen").first()).toBeVisible();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user