Files
florian.wildeandClaude Opus 5 ecc3c579df
Prüfung / pruefung (push) Canceled after 0s
Prüfung / e2e (push) Canceled after 0s
feat(mandant): Betriebsmodus, Kundenverwaltung und Einstellungen (#22)
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>
2026-09-25 05:03:11 +00:00

505 lines
22 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { Betriebsmodus } from "@/generated/prisma/enums";
import {
MandantFehler,
betriebsmodus,
eigeneOrganisation,
kundeErmitteln,
kundeZugriffPruefen,
kundenEbeneSichtbar,
sichtbareKundenIds,
} from "@/server/mandant";
import {
EinstellungsFehler,
einstellungenHolen,
einstellungenSpeichern,
modusWechseln,
modusWechselPruefen,
} from "@/server/services/einstellungen";
import { kundenListe, kundenZurAuswahl } from "@/server/queries/kunden";
import { datenbankLeeren, datenbankVerfuegbar, testPrisma } from "./helpers/db";
/**
* Betriebsmodus und Mandantengrenze (#008).
*
* Hier haengen die Akzeptanzkriterien, die den ganzen Zwei-Modi-Entwurf tragen:
* dass im Modus INTERN eine mitgeschickte kundeId verworfen wird, dass der
* Wechsel alle Daten mitnimmt und dass der Rueckweg bei zwei Kunden abgelehnt
* wird.
*
* `betriebsmodus()` benutzt Reacts `cache`. Ausserhalb einer Anfrage merkt das
* nichts – nachgeprueft –, die Tests beeinflussen sich also nicht gegenseitig.
*/
const UMGEBUNG = { ...process.env };
async function grundbestand(modus: Betriebsmodus = Betriebsmodus.INTERN) {
const organisation = await testPrisma.kunde.create({
data: { name: "Eigene Organisation", kuerzel: "EIGEN", istEigeneOrganisation: true },
});
await testPrisma.einstellung.create({ data: { id: "global", modus } });
const admin = await testPrisma.benutzer.create({
data: { email: "admin@firma.example", name: "Administrator", rolle: "ADMIN" },
});
return { organisation, admin };
}
describe.runIf(datenbankVerfuegbar)("Betriebsmodus und Mandantengrenze", () => {
beforeEach(async () => {
await datenbankLeeren();
delete process.env["OIDC_CUSTOMER_GROUP_PREFIX"];
});
afterEach(() => {
process.env = { ...UMGEBUNG };
});
describe("Modus lesen", () => {
it("ist INTERN, solange nichts eingestellt ist", async () => {
// Der sichere Standard: keine Kundenebene, nichts faellt auseinander.
expect(await betriebsmodus()).toBe(Betriebsmodus.INTERN);
});
it("liest den eingestellten Modus aus der Datenbank", async () => {
await grundbestand(Betriebsmodus.DIENSTLEISTUNG);
expect(await betriebsmodus()).toBe(Betriebsmodus.DIENSTLEISTUNG);
});
it("zeigt die Kundenebene nur im Modus Dienstleistung", async () => {
await grundbestand(Betriebsmodus.INTERN);
expect(await kundenEbeneSichtbar()).toBe(false);
await testPrisma.einstellung.update({
where: { id: "global" },
data: { modus: Betriebsmodus.DIENSTLEISTUNG },
});
expect(await kundenEbeneSichtbar()).toBe(true);
});
it("sagt deutlich Bescheid, wenn die eigene Organisation fehlt", async () => {
await expect(eigeneOrganisation()).rejects.toThrow(/pnpm db:seed/);
});
});
describe("kundeErmitteln", () => {
/** Ein Administrator – die Sichtbarkeit schraenkt ihn nie ein. */
const ADMIN = { id: "admin", rolle: "ADMIN" } as const;
it("verwirft im Modus Intern eine mitgeschickte fremde kundeId", async () => {
// Das ist die Regel, die den Zwei-Modi-Entwurf sicher macht: im Modus
// INTERN gibt es keine Kundenwahl, also ist auch nichts zu entscheiden.
const { organisation } = await grundbestand(Betriebsmodus.INTERN);
const fremder = await testPrisma.kunde.create({
data: { name: "Fremdfirma", kuerzel: "FREMD" },
});
expect(await kundeErmitteln(fremder.id, ADMIN)).toBe(organisation.id);
expect(await kundeErmitteln("gibt-es-gar-nicht", ADMIN)).toBe(organisation.id);
expect(await kundeErmitteln(null, ADMIN)).toBe(organisation.id);
expect(await kundeErmitteln(undefined, ADMIN)).toBe(organisation.id);
});
it("verlangt im Modus Dienstleistung eine Wahl", async () => {
await grundbestand(Betriebsmodus.DIENSTLEISTUNG);
await expect(kundeErmitteln(undefined, ADMIN)).rejects.toBeInstanceOf(MandantFehler);
await expect(kundeErmitteln(" ", ADMIN)).rejects.toThrow(/Kunde gewählt/);
});
it("weist im Modus Dienstleistung einen unbekannten Kunden ab", async () => {
await grundbestand(Betriebsmodus.DIENSTLEISTUNG);
await expect(kundeErmitteln("gibt-es-nicht", ADMIN)).rejects.toThrow(/gibt es nicht/);
});
it("weist einen archivierten Kunden ab", async () => {
await grundbestand(Betriebsmodus.DIENSTLEISTUNG);
const archiviert = await testPrisma.kunde.create({
data: { name: "Alte Firma", kuerzel: "ALT", archiviert: true },
});
await expect(kundeErmitteln(archiviert.id, ADMIN)).rejects.toThrow(/archiviert/);
});
it("nimmt im Modus Dienstleistung einen gueltigen Kunden an", async () => {
await grundbestand(Betriebsmodus.DIENSTLEISTUNG);
const mus = await testPrisma.kunde.create({ data: { name: "Musterfirma", kuerzel: "MUS" } });
expect(await kundeErmitteln(mus.id, ADMIN)).toBe(mus.id);
});
it("weist einen Kunden ab, an den der Benutzer nicht gebunden ist", async () => {
// Die Sichtbarkeit steht in kundeErmitteln selbst, damit kein Aufrufer sie
// vergessen kann.
process.env["OIDC_CUSTOMER_GROUP_PREFIX"] = "lz-kunde-";
await grundbestand(Betriebsmodus.DIENSTLEISTUNG);
const meiner = await testPrisma.kunde.create({ data: { name: "Meiner", kuerzel: "MEIN" } });
const fremder = await testPrisma.kunde.create({ data: { name: "Fremder", kuerzel: "FREMD" } });
const techniker = await testPrisma.benutzer.create({
data: { email: "t@firma.example", name: "Techniker", rolle: "TECHNIKER" },
});
await testPrisma.benutzerKunde.create({
data: { benutzerId: techniker.id, kundeId: meiner.id },
});
expect(await kundeErmitteln(meiner.id, techniker)).toBe(meiner.id);
await expect(kundeErmitteln(fremder.id, techniker)).rejects.toThrow(/Berechtigung/);
});
});
describe("Sichtbare Kunden", () => {
async function technikerMitBindung() {
const { organisation } = await grundbestand(Betriebsmodus.DIENSTLEISTUNG);
const mus = await testPrisma.kunde.create({ data: { name: "Musterfirma", kuerzel: "MUS" } });
await testPrisma.kunde.create({ data: { name: "Baeckerei", kuerzel: "REI" } });
const techniker = await testPrisma.benutzer.create({
data: { email: "t@firma.example", name: "Techniker", rolle: "TECHNIKER" },
});
await testPrisma.benutzerKunde.create({
data: { benutzerId: techniker.id, kundeId: mus.id },
});
return { organisation, mus, techniker };
}
it("schraenkt ohne gesetztes Praefix niemanden ein", async () => {
// Eine leere Bindung darf nicht als "sieht nichts" gelesen werden.
const { techniker } = await technikerMitBindung();
expect(await sichtbareKundenIds(techniker)).toBeUndefined();
});
it("schraenkt Techniker und Leser auf ihre Kunden ein", async () => {
process.env["OIDC_CUSTOMER_GROUP_PREFIX"] = "lz-kunde-";
const { mus, techniker } = await technikerMitBindung();
expect(await sichtbareKundenIds(techniker)).toEqual([mus.id]);
});
it("schraenkt Administrator und Redakteur nie ein", async () => {
process.env["OIDC_CUSTOMER_GROUP_PREFIX"] = "lz-kunde-";
await technikerMitBindung();
for (const rolle of ["ADMIN", "REDAKTEUR"] as const) {
expect(await sichtbareKundenIds({ id: "egal", rolle })).toBeUndefined();
}
});
it("schraenkt im Modus Intern nie ein", async () => {
process.env["OIDC_CUSTOMER_GROUP_PREFIX"] = "lz-kunde-";
await grundbestand(Betriebsmodus.INTERN);
const leser = await testPrisma.benutzer.create({
data: { email: "l@firma.example", name: "Leser", rolle: "LESER" },
});
expect(await sichtbareKundenIds(leser)).toBeUndefined();
});
it("weist den Zugriff auf einen fremden Kunden ab", async () => {
process.env["OIDC_CUSTOMER_GROUP_PREFIX"] = "lz-kunde-";
const { organisation, mus, techniker } = await technikerMitBindung();
await expect(kundeZugriffPruefen(mus.id, techniker)).resolves.toBeUndefined();
await expect(kundeZugriffPruefen(organisation.id, techniker)).rejects.toBeInstanceOf(MandantFehler);
});
});
describe("Wechsel nach Dienstleistung", () => {
it("nimmt alle Daten auf den ersten Kunden mit", async () => {
const { organisation, admin } = await grundbestand(Betriebsmodus.INTERN);
await testPrisma.geraet.create({
data: {
kundeId: organisation.id,
tagCode: "LZ-7K3F9Q",
hostname: "PC-001",
registriertAm: new Date(),
},
});
await testPrisma.mitarbeiter.create({
data: {
kundeId: organisation.id,
vorname: "Maria",
nachname: "Huber",
anzeigename: "Maria Huber",
},
});
await testPrisma.abteilung.create({
data: { kundeId: organisation.id, name: "Buchhaltung" },
});
const vorlage = await testPrisma.vorlage.create({ data: { name: "PC Neuinstallation" } });
const version = await testPrisma.vorlagenVersion.create({
data: {
vorlageId: vorlage.id,
version: 1,
status: "VEROEFFENTLICHT",
veroeffentlichtAm: new Date(),
},
});
await testPrisma.lauf.create({
data: {
vorlagenVersionId: version.id,
titel: "PC-001 neu aufsetzen",
kundeId: organisation.id,
erstelltVonId: admin.id,
},
});
await modusWechseln(
Betriebsmodus.DIENSTLEISTUNG,
{ name: "Musterfirma GmbH", kuerzel: "mus" },
admin.id,
);
expect(await betriebsmodus()).toBe(Betriebsmodus.DIENSTLEISTUNG);
const danach = await testPrisma.kunde.findUniqueOrThrow({ where: { id: organisation.id } });
expect(danach.name).toBe("Musterfirma GmbH");
// Das Kuerzel wird in Grossbuchstaben normalisiert.
expect(danach.kuerzel).toBe("MUS");
// Es bleibt dieselbe Zeile, deshalb haengt nichts um.
expect(await testPrisma.geraet.count({ where: { kundeId: organisation.id } })).toBe(1);
expect(await testPrisma.mitarbeiter.count({ where: { kundeId: organisation.id } })).toBe(1);
expect(await testPrisma.abteilung.count({ where: { kundeId: organisation.id } })).toBe(1);
expect(await testPrisma.lauf.count({ where: { kundeId: organisation.id } })).toBe(1);
expect(await testPrisma.kunde.count()).toBe(1);
});
it("weist ein ungueltiges Kuerzel mit einer verstaendlichen Meldung ab", async () => {
const { admin } = await grundbestand(Betriebsmodus.INTERN);
for (const kuerzel of ["X", "ZULANG7", "MU-S"]) {
await expect(
modusWechseln(Betriebsmodus.DIENSTLEISTUNG, { name: "Firma", kuerzel }, admin.id),
).rejects.toThrow(/2 bis 6/);
}
// Nach einem abgelehnten Wechsel steht der Modus unveraendert.
expect(await betriebsmodus()).toBe(Betriebsmodus.INTERN);
});
it("weist ein bereits vergebenes Kuerzel ab", async () => {
const { admin } = await grundbestand(Betriebsmodus.INTERN);
await testPrisma.kunde.create({ data: { name: "Andere", kuerzel: "MUS" } });
await expect(
modusWechseln(Betriebsmodus.DIENSTLEISTUNG, { name: "Firma", kuerzel: "MUS" }, admin.id),
).rejects.toThrow(/gehört bereits/);
});
it("behaelt Name und Kuerzel, wenn nichts angegeben wird", async () => {
const { organisation, admin } = await grundbestand(Betriebsmodus.INTERN);
await modusWechseln(Betriebsmodus.DIENSTLEISTUNG, {}, admin.id);
const danach = await testPrisma.kunde.findUniqueOrThrow({ where: { id: organisation.id } });
expect(danach.name).toBe(organisation.name);
expect(danach.kuerzel).toBe(organisation.kuerzel);
});
it("haelt den Wechsel im Protokoll fest", async () => {
const { admin } = await grundbestand(Betriebsmodus.INTERN);
await modusWechseln(Betriebsmodus.DIENSTLEISTUNG, { name: "Firma", kuerzel: "FIR" }, admin.id);
const eintrag = await testPrisma.protokoll.findFirstOrThrow({
where: { aktion: "Betriebsmodus gewechselt" },
});
expect(eintrag.benutzerId).toBe(admin.id);
expect(eintrag.vorher).toMatchObject({ modus: "INTERN" });
expect(eintrag.nachher).toMatchObject({ modus: "DIENSTLEISTUNG" });
});
});
describe("Wechsel zurueck nach Intern", () => {
it("wird bei zwei nicht archivierten Kunden abgelehnt", async () => {
const { admin } = await grundbestand(Betriebsmodus.DIENSTLEISTUNG);
await testPrisma.kunde.create({ data: { name: "Zweiter Kunde", kuerzel: "ZWEI" } });
const pruefung = await modusWechselPruefen(Betriebsmodus.INTERN);
expect(pruefung.moeglich).toBe(false);
expect(pruefung.grund).toMatch(/genau einem nicht archivierten Kunden/);
await expect(modusWechseln(Betriebsmodus.INTERN, {}, admin.id)).rejects.toBeInstanceOf(
EinstellungsFehler,
);
expect(await betriebsmodus()).toBe(Betriebsmodus.DIENSTLEISTUNG);
});
it("gelingt, sobald die uebrigen Kunden archiviert sind", async () => {
const { organisation, admin } = await grundbestand(Betriebsmodus.DIENSTLEISTUNG);
const zweiter = await testPrisma.kunde.create({
data: { name: "Zweiter Kunde", kuerzel: "ZWEI" },
});
await testPrisma.kunde.update({ where: { id: zweiter.id }, data: { archiviert: true } });
await modusWechseln(Betriebsmodus.INTERN, {}, admin.id);
expect(await betriebsmodus()).toBe(Betriebsmodus.INTERN);
expect((await eigeneOrganisation()).id).toBe(organisation.id);
// Archivierte Kunden bleiben archiviert und tauchen nicht wieder auf.
const archivierter = await testPrisma.kunde.findUniqueOrThrow({ where: { id: zweiter.id } });
expect(archivierter.archiviert).toBe(true);
});
it("haelt auch den Rueckweg im Protokoll fest", async () => {
const { admin } = await grundbestand(Betriebsmodus.DIENSTLEISTUNG);
await modusWechseln(Betriebsmodus.INTERN, {}, admin.id);
const eintrag = await testPrisma.protokoll.findFirstOrThrow({
where: { aktion: "Betriebsmodus gewechselt" },
});
expect(eintrag.vorher).toMatchObject({ modus: "DIENSTLEISTUNG" });
expect(eintrag.nachher).toMatchObject({ modus: "INTERN" });
});
it("lehnt den Wechsel in den bereits eingestellten Modus ab", async () => {
const { admin } = await grundbestand(Betriebsmodus.INTERN);
const pruefung = await modusWechselPruefen(Betriebsmodus.INTERN);
expect(pruefung.moeglich).toBe(false);
await expect(modusWechseln(Betriebsmodus.INTERN, {}, admin.id)).rejects.toThrow(/bereits/);
});
});
describe("Der Wechsel ist unteilbar", () => {
it("nimmt den Moduswechsel zurueck, wenn das Protokoll nicht geschrieben werden kann", async () => {
// Frueher stand der Protokoll-Eintrag hinter der Transaktion: schlug er
// fehl, war der Modus schon gewechselt und der Vorgang stand nirgends.
await grundbestand(Betriebsmodus.INTERN);
await expect(
modusWechseln(
Betriebsmodus.DIENSTLEISTUNG,
{ name: "Firma", kuerzel: "FIR" },
"diesen-benutzer-gibt-es-nicht",
),
).rejects.toThrow();
expect(await betriebsmodus()).toBe(Betriebsmodus.INTERN);
expect(await testPrisma.protokoll.count()).toBe(0);
// Auch Name und Kuerzel duerfen nicht halb geaendert sein.
const organisation = await testPrisma.kunde.findFirstOrThrow({
where: { istEigeneOrganisation: true },
});
expect(organisation.name).toBe("Eigene Organisation");
expect(organisation.kuerzel).toBe("EIGEN");
});
it("laesst von zwei gleichzeitigen Wechseln nur einen durch", async () => {
// Ohne Schloss liefen beide durch, mit zwei Protokolleintraegen, die beide
// INTERN als Vorzustand behaupteten.
const { admin } = await grundbestand(Betriebsmodus.INTERN);
const ergebnisse = await Promise.allSettled([
modusWechseln(Betriebsmodus.DIENSTLEISTUNG, { name: "Erster", kuerzel: "AAA" }, admin.id),
modusWechseln(Betriebsmodus.DIENSTLEISTUNG, { name: "Zweiter", kuerzel: "BBB" }, admin.id),
]);
expect(ergebnisse.filter((e) => e.status === "fulfilled")).toHaveLength(1);
expect(await testPrisma.protokoll.count({ where: { aktion: "Betriebsmodus gewechselt" } })).toBe(1);
});
});
describe("Lesemodelle wenden die Mandantensicht selbst an", () => {
it("zeigt einem gebundenen Techniker nur seine Kunden", async () => {
// Ein vergessener Filter waere hier kein Schoenheitsfehler, deshalb steht
// die Einschraenkung im Lesemodell und nicht beim Aufrufer.
process.env["OIDC_CUSTOMER_GROUP_PREFIX"] = "lz-kunde-";
await grundbestand(Betriebsmodus.DIENSTLEISTUNG);
const meiner = await testPrisma.kunde.create({ data: { name: "Meiner", kuerzel: "MEIN" } });
await testPrisma.kunde.create({ data: { name: "Fremder", kuerzel: "FREMD" } });
const techniker = await testPrisma.benutzer.create({
data: { email: "t@firma.example", name: "Techniker", rolle: "TECHNIKER" },
});
await testPrisma.benutzerKunde.create({
data: { benutzerId: techniker.id, kundeId: meiner.id },
});
const fuerTechniker = await kundenListe(techniker, true);
expect(fuerTechniker.map((z) => z.kuerzel)).toEqual(["MEIN"]);
expect((await kundenZurAuswahl(techniker)).map((z) => z.kuerzel)).toEqual(["MEIN"]);
// Der Administrator sieht weiterhin alles.
const fuerAdmin = await kundenListe({ id: "admin", rolle: "ADMIN" }, true);
expect(fuerAdmin).toHaveLength(3);
});
it("zeigt einem ungebundenen Techniker nichts, statt versehentlich alles", async () => {
// Der Unterschied zwischen "keine Einschraenkung" und "sieht nichts" ist
// der heikelste Teil dieser Regel.
process.env["OIDC_CUSTOMER_GROUP_PREFIX"] = "lz-kunde-";
await grundbestand(Betriebsmodus.DIENSTLEISTUNG);
await testPrisma.kunde.create({ data: { name: "Fremder", kuerzel: "FREMD" } });
const techniker = await testPrisma.benutzer.create({
data: { email: "t@firma.example", name: "Techniker", rolle: "TECHNIKER" },
});
expect(await kundenListe(techniker, true)).toEqual([]);
});
it("schraenkt ohne Praefix niemanden ein", async () => {
await grundbestand(Betriebsmodus.DIENSTLEISTUNG);
await testPrisma.kunde.create({ data: { name: "Fremder", kuerzel: "FREMD" } });
const techniker = await testPrisma.benutzer.create({
data: { email: "t@firma.example", name: "Techniker", rolle: "TECHNIKER" },
});
expect(await kundenListe(techniker, true)).toHaveLength(2);
});
});
describe("Wechsel-Auskunft fuer den Bestaetigungsdialog", () => {
it("nennt die Folgen und fragt nach Name und Kuerzel", async () => {
await grundbestand(Betriebsmodus.INTERN);
const pruefung = await modusWechselPruefen(Betriebsmodus.DIENSTLEISTUNG);
expect(pruefung.moeglich).toBe(true);
expect(pruefung.brauchtAngaben).toBe(true);
expect(pruefung.folgen.length).toBeGreaterThan(2);
expect(pruefung.folgen.join(" ")).toMatch(/erste[nr] Kunden/);
});
it("braucht fuer den Rueckweg keine Angaben", async () => {
await grundbestand(Betriebsmodus.DIENSTLEISTUNG);
const pruefung = await modusWechselPruefen(Betriebsmodus.INTERN);
expect(pruefung.moeglich).toBe(true);
expect(pruefung.brauchtAngaben).toBe(false);
});
});
describe("Einstellungen", () => {
it("liefert Modus, Regeln und die eigene Organisation", async () => {
await grundbestand(Betriebsmodus.INTERN);
const einstellungen = await einstellungenHolen();
expect(einstellungen.modus).toBe(Betriebsmodus.INTERN);
expect(einstellungen.eigeneOrganisation.kuerzel).toBe("EIGEN");
expect(einstellungen.namensregeln).toEqual({});
});
it("speichert Namensregeln und Sperr-OU und protokolliert es", async () => {
const { admin } = await grundbestand();
await einstellungenSpeichern(
{
namensregeln: { upn: "{vorname}.{nachname}@firma.de", sam: "{v}{nachname}" },
gesperrteOu: "OU=Gesperrt,DC=firma,DC=local",
},
admin.id,
);
const danach = await einstellungenHolen();
expect(danach.namensregeln.upn).toBe("{vorname}.{nachname}@firma.de");
expect(danach.gesperrteOu).toBe("OU=Gesperrt,DC=firma,DC=local");
expect(await testPrisma.protokoll.count({ where: { aktion: "Einstellungen geändert" } })).toBe(1);
});
it("benennt die eigene Organisation um", async () => {
const { organisation, admin } = await grundbestand();
await einstellungenSpeichern({ eigeneOrganisationName: " Wilde IT " }, admin.id);
const danach = await testPrisma.kunde.findUniqueOrThrow({ where: { id: organisation.id } });
expect(danach.name).toBe("Wilde IT");
});
it("weist einen leeren Namen ab", async () => {
const { admin } = await grundbestand();
await expect(
einstellungenSpeichern({ eigeneOrganisationName: " " }, admin.id),
).rejects.toBeInstanceOf(EinstellungsFehler);
});
it("schreibt nichts, wenn sich nichts aendert", async () => {
const { admin } = await grundbestand();
await einstellungenSpeichern({ namensregeln: {}, gesperrteOu: null }, admin.id);
expect(await testPrisma.protokoll.count()).toBe(0);
});
it("uebersteht einen unbrauchbaren Json-Inhalt in den Namensregeln", async () => {
// Ein von Hand verbogener Wert darf die Einstellungsseite nicht sprengen.
await grundbestand();
await testPrisma.einstellung.update({
where: { id: "global" },
data: { namensregeln: { upn: 42, unsinn: true } },
});
const einstellungen = await einstellungenHolen();
expect(einstellungen.namensregeln).toEqual({});
});
});
});