Files
betreuungs-cockpit/tests/berichte.test.ts
T
Florian Wilde 1ed19eb76e Zeilenenden der 24 verbliebenen Dateien normalisieren
Ausschliesslich Zeilenenden. Nachgewiesen mit
"git diff --cached --ignore-cr-at-eol": Der Diff ist leer, es hat sich
kein Zeichen Inhalt geaendert.

Deshalb ein eigener Commit: 7448 geaenderte Zeilen in einem Commit mit
echten Aenderungen zu verstecken, macht die Historie an dieser Stelle
unlesbar. So laesst er sich beim Durchsehen ueberspringen.

Refs #26
2026-08-23 23:37:02 +02:00

666 lines
23 KiB
TypeScript
Raw 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 { readFileSync } from 'node:fs'
import path from 'node:path'
import { describe, expect, it } from 'vitest'
import {
ERGAENZEN,
GLIEDERUNG,
aufzaehlung,
dauerAusgeschrieben,
entwurfAlsText,
jahresberichtEntwurfBauen,
jahresberichtEntwurfText,
malAngabe,
offeneErgaenzungen,
textZuAbschnitten,
type JahresberichtQuellen,
} from '@/lib/berichte/jahresbericht.entwurf'
import {
berichtDateiname,
exportDokumentPfad,
pfadIstSicher,
sichereEndung,
sichererDateiname,
belegmappeSchema,
unterlagenpaketSchema,
jahresberichtErzeugenSchema,
} from '@/lib/validierung/berichte'
import {
HinweisdateiSchema,
ausloeserPasst,
hinweiseAusDaten,
hinweiseAusText,
hinweiseSuchen,
passendeHinweise,
type Hinweiskarte,
} from '@/lib/hinweise/laden'
import {
beschreibbareModule,
freigabeAenderung,
freigabenNormalisieren,
letzterAdminGeschuetzt,
sichtbareModule,
} from '@/lib/validierung/freigaben'
import { darf } from '@/lib/auth/rollen'
// -----------------------------------------------------------------------------
// Beispieldaten - ein Jahr im Leben einer betreuten Person
// -----------------------------------------------------------------------------
const tag = (iso: string) => new Date(`${iso}T00:00:00.000Z`)
function beispiel(aenderungen: Partial<JahresberichtQuellen> = {}): JahresberichtQuellen {
const quellen: JahresberichtQuellen = {
betreute: {
anrede: 'Frau',
vorname: 'Maria',
nachname: 'Musterfrau',
geburtsdatum: tag('1943-04-17'),
heimName: 'Seniorenzentrum St. Anna',
heimStrasse: 'Klinikweg 4',
heimPlz: '95444',
heimOrt: 'Bayreuth',
heimZimmer: '212',
heimEinzugAm: tag('2025-11-03'),
fruehereStrasse: 'Bergstraße 12',
frueherePlz: '95463',
fruehererOrt: 'Bindlach',
pflegegrad: 4,
pflegegradSeit: tag('2025-12-01'),
schwerbehinderungGdB: 80,
schwerbehinderungMerkzeichen: 'G, B',
diagnosen: 'COPD GOLD III mit Sauerstoffpflicht, Herzinsuffizienz',
ermittelterWille: 'Sie möchte nicht wiederbelebt werden und keine künstliche Ernährung.',
patientenverfuegungVorhanden: true,
vorsorgevollmachtVorhanden: false,
aufgabenkreise: ['VERMOEGENSSORGE', 'GESUNDHEITSSORGE'],
aufgabenkreiseFreitext: null,
betreuungsgericht: 'Amtsgericht Bayreuth',
aktenzeichenGericht: 'XVII 123/25',
bestellungAm: tag('2025-10-01'),
bestellungBis: null,
},
zeitraumVon: tag('2025-10-01'),
zeitraumBis: tag('2026-09-30'),
kontakte: [
{
datum: tag('2025-11-10'),
art: 'BESUCH',
mitBetreuter: true,
dauerMinuten: 90,
gespraechspartner: null,
wuensche: 'Sie möchte ihre Nähmaschine im Zimmer haben.',
},
{
datum: tag('2026-02-14'),
art: 'BESUCH',
mitBetreuter: true,
dauerMinuten: 60,
gespraechspartner: null,
wuensche: null,
},
{
datum: tag('2026-06-20'),
art: 'TELEFONAT',
mitBetreuter: true,
dauerMinuten: 15,
gespraechspartner: null,
wuensche: 'Das Haus in Bindlach soll nicht verkauft werden.',
},
{
datum: tag('2026-03-02'),
art: 'TELEFONAT',
mitBetreuter: false,
dauerMinuten: 20,
gespraechspartner: 'Bezirk Oberfranken',
wuensche: null,
},
],
gesundheit: [
{
datum: tag('2026-01-08'),
bisDatum: tag('2026-01-19'),
art: 'KRANKENHAUS',
titel: 'Exazerbation der COPD',
einrichtung: 'Klinikum Bayreuth',
abwesenheitstage: 11,
},
{
datum: tag('2026-04-03'),
bisDatum: null,
art: 'ARZTBESUCH',
titel: 'Kontrolle Lungenfacharzt',
einrichtung: null,
abwesenheitstage: null,
},
],
vorgaenge: [
{
titel: 'Antrag auf Hilfe zur Pflege',
kategorie: 'SOZIALHILFE',
status: 'WARTET_AUF_DRITTE',
naechsterSchritt: 'Sachstandsanfrage beim Bezirk',
gegenstelle: 'Bezirk Oberfranken',
genehmigungspflichtig: false,
erledigtAm: null,
},
{
titel: 'Wohnung Bindlach auflösen',
kategorie: 'IMMOBILIE',
status: 'ERLEDIGT',
naechsterSchritt: null,
gegenstelle: null,
genehmigungspflichtig: true,
erledigtAm: tag('2026-05-12'),
},
],
}
return { ...quellen, ...aenderungen }
}
// -----------------------------------------------------------------------------
// Jahresbericht
// -----------------------------------------------------------------------------
describe('Jahresbericht nach § 1863 BGB', () => {
it('führt alle fünf Punkte auf, die das Gericht sehen will', () => {
const abschnitte = jahresberichtEntwurfBauen(beispiel())
expect(abschnitte).toHaveLength(5)
expect(abschnitte.map((a) => a.nummer)).toEqual([1, 2, 3, 4, 5])
expect(abschnitte.map((a) => a.titel)).toEqual(GLIEDERUNG.map((g) => g.titel))
for (const abschnitt of abschnitte) {
expect(abschnitt.absaetze.length).toBeGreaterThan(0)
expect(abschnitt.rechtsgrundlage).toMatch(/§/)
}
})
it('beschreibt den Aufenthalt, den Pflegegrad und den Krankenhausaufenthalt', () => {
const [persoenlich] = jahresberichtEntwurfBauen(beispiel())
const text = persoenlich!.absaetze.join('\n')
expect(text).toContain('Seniorenzentrum St. Anna')
expect(text).toContain('Zimmer 212')
expect(text).toContain('Pflegegrad 4')
expect(text).toContain('COPD GOLD III')
expect(text).toContain('Klinikum Bayreuth')
expect(text).toContain('11 Abwesenheitstage')
expect(text).toContain('Patientenverfügung liegt vor')
})
it('zählt die persönlichen Kontakte und schreibt sie in ganzen Sätzen aus', () => {
const [, kontakt] = jahresberichtEntwurfBauen(beispiel())
const text = kontakt!.absaetze.join('\n')
// Drei Kontakte mit der betreuten Person, davon zwei Besuche.
expect(text).toContain('dreimal persönlichen Kontakt')
expect(text).toContain('2 Besuche')
expect(text).toContain('ein Telefonat')
// Der Kontakt mit dem Bezirk zählt nicht als persönlicher Kontakt.
expect(text).toContain('1 Kontakte mit Dritten')
expect(text).toContain('Bezirk Oberfranken')
expect(text).toContain('2 Stunden und 45 Minuten')
})
it('warnt ausdrücklich, wenn kein persönlicher Kontakt protokolliert ist', () => {
const ohne = beispiel({ kontakte: [] })
const [, kontakt] = jahresberichtEntwurfBauen(ohne)
const text = kontakt!.absaetze.join('\n')
expect(text).toContain('kein persönlicher Kontakt')
expect(text).toContain('§ 1863 Abs. 2 BGB')
})
it('übernimmt die Wünsche aus den Protokollen und nennt § 1821 BGB', () => {
const [, , wuensche] = jahresberichtEntwurfBauen(beispiel())
const text = wuensche!.absaetze.join('\n')
expect(text).toContain('§ 1821 BGB')
expect(text).toContain('Nähmaschine')
expect(text).toContain('Das Haus in Bindlach soll nicht verkauft werden.')
expect(text).toContain('nicht wiederbelebt werden')
// Der Betreuer muss selbst ergänzen, wie er den Wünschen entsprochen hat.
expect(text).toContain(ERGAENZEN)
})
it('trennt erledigte und laufende Angelegenheiten nach Kategorien', () => {
const [, , , angelegenheiten] = jahresberichtEntwurfBauen(beispiel())
const text = angelegenheiten!.absaetze.join('\n')
expect(text).toContain('Sozialhilfe und Hilfe zur Pflege')
expect(text).toContain('Immobilie und Wohnraum')
expect(text).toContain('Abgeschlossen wurde Wohnung Bindlach auflösen')
expect(text).toContain('Noch offen ist Antrag auf Hilfe zur Pflege')
expect(text).toContain('Sachstandsanfrage beim Bezirk')
expect(text).toContain('Genehmigungspflichtig waren dabei')
})
it('macht zur Fortführung einen Vorschlag und verlangt eine eigene Entscheidung', () => {
const [, , , , einschaetzung] = jahresberichtEntwurfBauen(beispiel())
const text = einschaetzung!.absaetze.join('\n')
expect(text).toContain('Vermögenssorge')
expect(text).toContain('Gesundheitssorge')
expect(text).toContain('fortzuführen')
expect(text).toContain('zu erweitern')
expect(text).toContain('einzuschränken')
expect(text).toContain(ERGAENZEN)
})
it('bleibt ein Entwurf: offene Stellen sind gezählt und wiederauffindbar', () => {
const text = jahresberichtEntwurfText(beispiel())
expect(offeneErgaenzungen(text)).toBeGreaterThan(0)
})
it('lässt sich als Text ablegen und wieder in Abschnitte zerlegen', () => {
const abschnitte = jahresberichtEntwurfBauen(beispiel())
const text = entwurfAlsText(abschnitte)
expect(text.startsWith('1. Persönliche Verhältnisse')).toBe(true)
const zurueck = textZuAbschnitten(text)
expect(zurueck).toHaveLength(5)
expect(zurueck[1]!.titel).toBe('2. Persönlicher Kontakt zur betreuten Person')
expect(zurueck[4]!.absaetze.length).toBeGreaterThan(0)
})
it('verkraftet einen leeren Bestand, ohne den Bericht zu verstümmeln', () => {
const leer = beispiel({ kontakte: [], gesundheit: [], vorgaenge: [] })
const abschnitte = jahresberichtEntwurfBauen(leer)
expect(abschnitte).toHaveLength(5)
for (const abschnitt of abschnitte) {
expect(abschnitt.absaetze.join('').trim()).not.toBe('')
}
})
it('formuliert Zahl- und Zeitangaben so, wie man sie schreiben würde', () => {
expect(malAngabe(0)).toBe('keinmal')
expect(malAngabe(1)).toBe('einmal')
expect(malAngabe(3)).toBe('dreimal')
expect(malAngabe(17)).toBe('17-mal')
expect(dauerAusgeschrieben(95)).toBe('1 Stunde und 35 Minuten')
expect(dauerAusgeschrieben(45)).toBe('45 Minuten')
expect(aufzaehlung(['a', 'b', 'c'])).toBe('a, b und c')
expect(aufzaehlung(['a'])).toBe('a')
expect(aufzaehlung([])).toBe('')
})
})
// -----------------------------------------------------------------------------
// Dateinamen im Export
// -----------------------------------------------------------------------------
describe('Dateinamen im Vollexport', () => {
it('schreibt Umlaute um und lässt nur harmlose Zeichen stehen', () => {
expect(sichererDateiname('Bescheid Hilfe zur Pflege')).toBe('Bescheid-Hilfe-zur-Pflege')
expect(sichererDateiname('Vergütung & Rückkauf')).toBe('Verguetung-Rueckkauf')
expect(sichererDateiname('Maßnahme')).toBe('Massnahme')
expect(sichererDateiname(' ')).toBe('ohne-titel')
expect(sichererDateiname('...')).toBe('ohne-titel')
})
it('lässt keinen Pfadausbruch zu', () => {
for (const boesartig of [
'../../etc/passwd',
'..\\..\\windows\\system32',
'C:\\Users\\Public\\x',
'/etc/shadow',
'beleg\u0000.pdf',
'auszug:stream',
]) {
const sauber = sichererDateiname(boesartig)
expect(sauber).not.toContain('..')
expect(sauber).not.toContain('/')
expect(sauber).not.toContain('\\')
expect(sauber).not.toContain(':')
expect(sauber).not.toContain('\u0000')
}
})
it('umgeht Namen, die Windows nie akzeptiert', () => {
expect(sichererDateiname('CON')).toBe('_CON')
expect(sichererDateiname('lpt1')).toBe('_lpt1')
})
it('baut den Dokumentpfad nach dem verabredeten Muster', () => {
const pfad = exportDokumentPfad({
datum: tag('2026-03-14'),
absender: 'Bezirk Oberfranken',
titel: 'Bescheid über Hilfe zur Pflege',
dateiname: 'scan.PDF',
mimeTyp: 'application/pdf',
})
expect(pfad).toBe(
'dokumente/2026/2026-03-14_Bezirk-Oberfranken_Bescheid-ueber-Hilfe-zur-Pflege.pdf',
)
expect(pfadIstSicher(pfad)).toBe(true)
})
it('legt Dokumente ohne Datum in einen eigenen Ordner statt in ein erfundenes Jahr', () => {
const pfad = exportDokumentPfad({
datum: null,
absender: null,
titel: '../../geheim',
dateiname: null,
mimeTyp: 'image/jpeg',
})
expect(pfad.startsWith('dokumente/ohne-jahr/')).toBe(true)
expect(pfad.endsWith('.jpg')).toBe(true)
expect(pfad.split('/')).toHaveLength(3)
expect(pfadIstSicher(pfad)).toBe(true)
})
it('erkennt unzulässige Archivpfade', () => {
expect(pfadIstSicher('daten/frist.json')).toBe(true)
expect(pfadIstSicher('dokumente/../../x')).toBe(false)
expect(pfadIstSicher('/absolut')).toBe(false)
expect(pfadIstSicher('C:/windows')).toBe(false)
expect(pfadIstSicher('a\\b')).toBe(false)
expect(pfadIstSicher('')).toBe(false)
expect(pfadIstSicher('a//b')).toBe(false)
})
it('normalisiert Dateiendungen', () => {
expect(sichereEndung('scan.PDF')).toBe('pdf')
expect(sichereEndung('pdf')).toBe('pdf')
expect(sichereEndung('ohnepunkt')).toBe('bin')
expect(sichereEndung('bild.jpeg')).toBe('jpeg')
expect(sichereEndung('x.verylongextension')).toBe('bin')
expect(sichereEndung(null)).toBe('bin')
})
it('benennt erzeugte Berichte sortierbar', () => {
expect(berichtDateiname('jahresbericht', 'Musterfrau', tag('2026-09-30'), 'pdf')).toBe(
'2026-09-30_jahresbericht_Musterfrau.pdf',
)
})
})
// -----------------------------------------------------------------------------
// Eingabepruefung
// -----------------------------------------------------------------------------
describe('Eingabeprüfung der Berichtsformulare', () => {
it('weist einen Berichtszeitraum zurück, der rückwärts läuft', () => {
const ergebnis = jahresberichtErzeugenSchema.safeParse({
betreuteId: 'abc123',
zeitraumVon: '2026-09-30',
zeitraumBis: '2025-10-01',
})
expect(ergebnis.success).toBe(false)
})
it('verlangt für die Belegmappe entweder einen Zeitraum oder einen Vorgang', () => {
expect(
belegmappeSchema.safeParse({ betreuteId: 'abc', quelle: 'zeitraum', zeitraumVon: '', zeitraumBis: '' })
.success,
).toBe(false)
expect(
belegmappeSchema.safeParse({
betreuteId: 'abc',
quelle: 'vorgang',
zeitraumVon: '',
zeitraumBis: '',
vorgangId: 'vg1',
}).success,
).toBe(true)
})
it('lässt ein Unterlagenpaket ohne ausgewählte Unterlage nicht zu', () => {
expect(
unterlagenpaketSchema.safeParse({ betreuteId: 'a', antragId: 'b', nachforderungIds: [] })
.success,
).toBe(false)
})
})
// -----------------------------------------------------------------------------
// Hinweis-Wissensbasis
// -----------------------------------------------------------------------------
const WISSENSBASIS = path.join(process.cwd(), 'daten', 'hinweise.json')
describe('Hinweis-Wissensbasis', () => {
const roh = readFileSync(WISSENSBASIS, 'utf8')
const geladen = hinweiseAusText(roh)
it('ist gültig gegen das Schema', () => {
expect(geladen.fehler).toEqual([])
expect(HinweisdateiSchema.safeParse(JSON.parse(roh)).success).toBe(true)
})
it('enthält mindestens 25 Karten mit eindeutigen Schlüsseln', () => {
expect(geladen.karten.length).toBeGreaterThanOrEqual(25)
const schluessel = geladen.karten.map((k) => k.schluessel)
expect(new Set(schluessel).size).toBe(schluessel.length)
})
it('nennt zu jeder Karte eine Rechtsgrundlage und einen sicheren Link', () => {
for (const karte of geladen.karten) {
expect(karte.rechtsgrundlage.length).toBeGreaterThan(1)
expect(karte.link.startsWith('https://')).toBe(true)
expect(karte.kontext.length).toBeGreaterThan(0)
}
})
it('deckt die fachlich unverzichtbaren Themen ab', () => {
const schluessel = new Set(geladen.karten.map((k) => k.schluessel))
for (const pflicht of [
'wohnraum-aufgeben',
'grundstueck-genehmigung',
'genehmigung-vor-geschaeft',
'aufwandspauschale',
'vermoegensverzeichnis-frist',
'jahresbericht',
'getrennte-konten',
'schonvermoegen',
'hausgrundstueck-geschuetzt',
'bestattungsvorsorge',
'darlehen-statt-verwertung',
'widerspruchsfrist',
'fehlende-rechtsbehelfsbelehrung',
'wille-leitschnur',
'zwangsmassnahme',
'unterbringung',
'leistungszuschlag',
'zuzahlungsbefreiung',
'landespflegegeld',
'rundfunkbeitragsbefreiung',
'pflegegrad-hoeherstufung',
'leerstand-versicherung',
'verkehrssicherungspflicht',
'schenkungsrueckforderung',
'betreuerausweis',
'kontoauszuege-aufbewahren',
'rechtspfleger-fragen',
]) {
expect(schluessel.has(pflicht), `Karte "${pflicht}" fehlt`).toBe(true)
}
})
it('markiert die Ausschlussfrist der Aufwandspauschale als solche', () => {
const karte = geladen.karten.find((k) => k.schluessel === 'aufwandspauschale')!
expect(karte.text).toContain('Ausschlussfrist')
expect(karte.rechtsgrundlage).toContain('1878')
})
it('meldet kaputtes JSON, statt abzustürzen', () => {
const ergebnis = hinweiseAusText('{ das ist kein JSON')
expect(ergebnis.karten).toEqual([])
expect(ergebnis.fehler.length).toBeGreaterThan(0)
})
it('lehnt Karten ohne Pflichtangaben ab', () => {
const ergebnis = hinweiseAusDaten({
version: 1,
karten: [{ schluessel: 'x', titel: 'zu kurz' }],
})
expect(ergebnis.karten).toEqual([])
expect(ergebnis.fehler.length).toBeGreaterThan(0)
})
it('erkennt doppelte Schlüssel', () => {
const eine = geladen.karten[0]!
const ergebnis = hinweiseAusDaten({ version: 1, karten: [eine, { ...eine }] })
expect(ergebnis.karten).toEqual([])
expect(ergebnis.fehler[0]).toContain('Doppelte Schlüssel')
})
})
describe('Zuordnung der Hinweiskarten zum Kontext', () => {
const karten: Hinweiskarte[] = [
{
schluessel: 'a',
titel: 'Karte A für die Immobilie',
text: 'x'.repeat(60),
rechtsgrundlage: '§ 1833 BGB',
link: 'https://www.gesetze-im-internet.de/bgb/__1833.html',
kontext: ['IMMOBILIE', 'VORLAGE:wohnungsaufloesung'],
gewicht: 5,
},
{
schluessel: 'b',
titel: 'Karte B zur Jahresberichtsfrist',
text: 'y'.repeat(60),
rechtsgrundlage: '§ 1863 BGB',
link: 'https://www.gesetze-im-internet.de/bgb/__1863.html',
kontext: ['FRIST:jahresbericht'],
gewicht: 9,
},
{
schluessel: 'c',
titel: 'Karte C zur Sozialhilfe',
text: 'z'.repeat(60),
rechtsgrundlage: '§ 90 SGB XII',
link: 'https://www.gesetze-im-internet.de/sgb_12/__90.html',
kontext: ['SOZIALHILFE', 'IMMOBILIE'],
gewicht: 9,
},
]
it('findet Karten über Modul, Vorlage und Frist', () => {
expect(passendeHinweise(karten, ['IMMOBILIE']).map((k) => k.schluessel)).toEqual(['c', 'a'])
expect(passendeHinweise(karten, ['VORLAGE:wohnungsaufloesung']).map((k) => k.schluessel)).toEqual([
'a',
])
expect(passendeHinweise(karten, ['FRISTEN'])).toEqual([])
})
it('lässt einen Auslöser auch auf die Frist mit Jahreszahl passen', () => {
expect(ausloeserPasst('FRIST:jahresbericht', 'FRIST:jahresbericht-2027')).toBe(true)
expect(ausloeserPasst('FRIST:jahresbericht', 'FRIST:jahresberichtXYZ')).toBe(false)
expect(ausloeserPasst('IMMOBILIE', 'immobilie')).toBe(true)
expect(passendeHinweise(karten, ['FRIST:jahresbericht-2027']).map((k) => k.schluessel)).toEqual([
'b',
])
})
it('sortiert nach Gewicht und bleibt bei Gleichstand stabil', () => {
const treffer = passendeHinweise(karten, ['IMMOBILIE', 'FRIST:jahresbericht'])
expect(treffer.map((k) => k.schluessel)).toEqual(['b', 'c', 'a'])
expect(passendeHinweise(karten, ['IMMOBILIE'], 1).map((k) => k.schluessel)).toEqual(['c'])
})
it('sucht über Titel, Text und Rechtsgrundlage', () => {
expect(hinweiseSuchen(karten, '1833').map((k) => k.schluessel)).toEqual(['a'])
expect(hinweiseSuchen(karten, 'sozialhilfe').map((k) => k.schluessel)).toEqual(['c'])
expect(hinweiseSuchen(karten, '').map((k) => k.schluessel)).toEqual(['b', 'c', 'a'])
})
})
// -----------------------------------------------------------------------------
// Rollen und Freigaben
// -----------------------------------------------------------------------------
describe('Mitleser-Rolle und Modulfreigaben', () => {
const mitleser = {
rolle: 'MITLESER' as const,
freigegebeneModule: ['STAMMDATEN', 'FRISTEN'] as const,
}
it('lässt einen Mitleser niemals schreiben – auch nicht im freigegebenen Modul', () => {
expect(darf({ ...mitleser, freigegebeneModule: [...mitleser.freigegebeneModule] }, 'FRISTEN', 'lesen')).toBe(true)
expect(darf({ ...mitleser, freigegebeneModule: [...mitleser.freigegebeneModule] }, 'FRISTEN', 'schreiben')).toBe(false)
expect(
beschreibbareModule({ rolle: 'MITLESER', freigegebeneModule: ['STAMMDATEN', 'FRISTEN'] }),
).toEqual([])
})
it('zeigt einem Mitleser nur die freigegebenen Bereiche', () => {
expect(sichtbareModule({ rolle: 'MITLESER', freigegebeneModule: ['STAMMDATEN', 'FRISTEN'] })).toEqual([
'STAMMDATEN',
'FRISTEN',
])
expect(darf({ rolle: 'MITLESER', freigegebeneModule: ['STAMMDATEN'] }, 'GESUNDHEIT', 'lesen')).toBe(
false,
)
})
it('gibt dem Betreuer und dem Administrator alles', () => {
expect(sichtbareModule({ rolle: 'BETREUER', freigegebeneModule: [] }).length).toBeGreaterThan(10)
expect(beschreibbareModule({ rolle: 'ADMIN', freigegebeneModule: [] }).length).toBeGreaterThan(10)
})
it('sperrt jeden Zugriff ohne Zugang', () => {
expect(darf(null, 'STAMMDATEN', 'lesen')).toBe(false)
expect(sichtbareModule(null)).toEqual([])
})
it('räumt die Modulliste auf, sobald jemand kein Mitleser mehr ist', () => {
expect(freigabenNormalisieren('BETREUER', ['GESUNDHEIT'])).toEqual([])
expect(freigabenNormalisieren('ADMIN', ['GESUNDHEIT'])).toEqual([])
expect(freigabenNormalisieren('MITLESER', ['FRISTEN', 'STAMMDATEN'])).toEqual([
'STAMMDATEN',
'FRISTEN',
])
})
it('benennt, was sich an einer Freigabe ändert – und was davon heikel ist', () => {
const aenderung = freigabeAenderung(
{ rolle: 'MITLESER', freigegebeneModule: ['STAMMDATEN', 'FRISTEN'] },
{ rolle: 'MITLESER', freigegebeneModule: ['STAMMDATEN', 'GESUNDHEIT', 'FINANZEN'] },
)
expect(aenderung.hinzugefuegt).toEqual(['FINANZEN', 'GESUNDHEIT'])
expect(aenderung.entfernt).toEqual(['FRISTEN'])
expect(aenderung.sensibelHinzugefuegt).toEqual(['FINANZEN', 'GESUNDHEIT'])
expect(aenderung.rolleGeaendert).toBe(false)
})
it('schützt den letzten Administrator vor sich selbst', () => {
expect(
letzterAdminGeschuetzt({
zielRolleVorher: 'ADMIN',
zielRolleNachher: 'BETREUER',
zielBleibtAktiv: true,
anzahlAktiverAdmins: 1,
}),
).toMatch(/letzte aktive Administrator/)
expect(
letzterAdminGeschuetzt({
zielRolleVorher: 'ADMIN',
zielRolleNachher: 'BETREUER',
zielBleibtAktiv: true,
anzahlAktiverAdmins: 2,
}),
).toBeNull()
expect(
letzterAdminGeschuetzt({
zielRolleVorher: 'BETREUER',
zielRolleNachher: 'MITLESER',
zielBleibtAktiv: true,
anzahlAktiverAdmins: 1,
}),
).toBeNull()
})
})