Zwei Betriebsmodi, ein Codepfad. src/server/mandant.ts ist die eine Stelle, an der die Mandantenregel steht. Der Review fand drei Blocker: die Lesemodelle wandten die Mandantensicht nicht an, der Protokolleintrag des Moduswechsels stand außerhalb der Transaktion, und Prüfung und Vollzug lagen so weit auseinander, dass zwei gleichzeitige Wechsel beide durchliefen. Alle drei geschlossen, der letzte mit einem Advisory Lock. 336 Tests. Closes #8 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
65 lines
2.3 KiB
TypeScript
65 lines
2.3 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { 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 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);
|
|
}
|
|
});
|
|
});
|