import { describe, expect, it } from "vitest"; import { existsSync } from "node:fs"; import { NAVIGATION, navigationFuer } from "@/lib/navigation"; import { darf } from "@/server/auth/rollen"; import type { Rolle } from "@/generated/prisma/enums"; /** Was die Seitenleiste je Betriebsmodus und Rolle zeigt (#005, #007). */ function pfadeFuer(modus: "INTERN" | "DIENSTLEISTUNG", rolle: Rolle): string[] { return navigationFuer(modus, (recht) => darf(rolle, recht)).map((e) => e.pfad); } describe("Seitenleiste nach Betriebsmodus", () => { it("zeigt im Modus Intern die Kunden-Ebene nicht", () => { const pfade = pfadeFuer("INTERN", "ADMIN"); expect(pfade).not.toContain("/kunden"); expect(pfade).toContain("/mitarbeiter"); }); it("zeigt im Modus Dienstleistung Kunden statt Mitarbeiter & Geräte", () => { const pfade = pfadeFuer("DIENSTLEISTUNG", "ADMIN"); expect(pfade).toContain("/kunden"); expect(pfade).not.toContain("/mitarbeiter"); }); }); describe("Seitenleiste nach Rolle", () => { it("zeigt Admin nur dem Administrator", () => { expect(pfadeFuer("INTERN", "ADMIN")).toContain("/admin"); for (const rolle of ["REDAKTEUR", "TECHNIKER", "LESER"] as const) { expect(pfadeFuer("INTERN", rolle), `Rolle ${rolle}`).not.toContain("/admin"); } }); it("zeigt einem Leser die fachlichen Bereiche, aber nichts Verwaltendes", () => { const pfade = pfadeFuer("INTERN", "LESER"); expect(pfade).toContain("/"); expect(pfade).toContain("/laeufe"); expect(pfade).toContain("/archiv"); expect(pfade).not.toContain("/admin"); }); it("blendet ohne bekannte Rolle alles Rechtegebundene aus", () => { // So sieht die Huelle aus, solange niemand angemeldet ist. const pfade = navigationFuer("INTERN", () => false).map((e) => e.pfad); expect(pfade).not.toContain("/admin"); }); }); describe("Aufbau der Eintraege", () => { it("verlinkt keinen Eintrag, dessen Seite es noch nicht gibt", () => { for (const eintrag of navigationFuer("INTERN")) { if (!eintrag.verfuegbar) { expect(eintrag.ausIssue, `${eintrag.pfad} braucht eine Issue-Nummer`).toBeGreaterThan(0); } } }); it("hat zu jedem verfuegbaren Eintrag auch eine Seite", () => { // Das Umstellen von `verfuegbar` ist ein Handgriff im Meilenstein, der die // Seite liefert. Wird es zu frueh gemacht, zeigt die Navigation auf eine // 404 – und genau das faellt beim Klicken selten auf, weil man die eigene // neue Seite kennt und die anderen nicht anfasst. for (const eintrag of NAVIGATION) { if (!eintrag.verfuegbar) continue; const teil = eintrag.pfad === "/" ? "" : eintrag.pfad; const seite = new URL(`../src/app/(app)${teil}/page.tsx`, import.meta.url); expect(existsSync(seite), `${eintrag.pfad} ist verfuegbar, hat aber keine page.tsx`).toBe(true); } }); it("hat keine doppelten Pfade je Modus", () => { for (const modus of ["INTERN", "DIENSTLEISTUNG"] as const) { const pfade = pfadeFuer(modus, "ADMIN"); expect(new Set(pfade).size).toBe(pfade.length); } }); });