Files
Harlekin e0b03ea336
Prüfung / Lint, Typen, Tests (push) Canceled after 0s
Prüfung / Images bauen (pdf) (push) Canceled after 0s
Prüfung / Images bauen (web) (push) Canceled after 0s
Prüfung / Images bauen (worker) (push) Canceled after 0s
Images / bauen (pdf, docker/pdf.Dockerfile) (push) Canceled after 0s
Images / bauen (web, docker/web.Dockerfile) (push) Canceled after 0s
Images / bauen (worker, docker/worker.Dockerfile) (push) Canceled after 0s
Gedankenstriche durch Bindestriche ersetzt
375 Vorkommen in 210 Dateien. Betrifft Kommentare, Oberflaechentexte und die
README; an keiner Stelle Bedeutung, nur Zeichensetzung.
2026-09-04 08:54:52 +02:00

125 lines
4.3 KiB
TypeScript

// @vitest-environment node
import { afterAll, describe, expect, it } from 'vitest'
import { db } from '@/lib/db'
import { parseTemplateFields } from '@/lib/templates/schema'
import { dossierRows, dossierSpan, isInputField } from '@/lib/templates/fields'
/**
* Das Aktenblatt der Personalabteilung.
*
* Der erste Test ist der wichtigere: `parseTemplateFields` gibt bei einer
* ungültigen Vorlage eine **leere Liste** zurück, statt zu werfen. Ein Tippfehler
* im Seed würde das Blatt also lautlos leeren, statt aufzufallen.
*/
const url = process.env.DIRECT_DATABASE_URL ?? process.env.DATABASE_URL
const suite = url ? describe : describe.skip
suite('Vorlage des Aktenblatts', () => {
afterAll(async () => {
await db.$disconnect()
})
async function felder() {
const vorlage = await db.documentTemplate.findFirst({
where: { key: 'personalakte', isActive: true },
orderBy: { version: 'desc' },
select: { fields: true, layout: true, uses: true, sheetTitle: true, sheetSubtitle: true },
})
expect(vorlage).not.toBeNull()
return { vorlage: vorlage!, fields: parseTemplateFields(vorlage!.fields) }
}
it('übersteht die verbindliche Prüfung vollständig', async () => {
const { vorlage, fields } = await felder()
// Kein stilles Leerlaufen: die Zahl muss stimmen, nicht nur "grösser null".
expect(fields).toHaveLength(
(vorlage.fields as unknown[]).length,
)
expect(vorlage.layout).toBe('DOSSIER')
expect(vorlage.uses).toEqual(['PERSON_DOCUMENT'])
expect(vorlage.sheetSubtitle).toBeTruthy()
// Die Felder, die das Blatt ausmachen.
const schluessel = fields.map((f) => f.key)
for (const key of [
'lichtbild',
'name',
'vorname',
'alter',
'geschlecht',
'groesse',
'abteilung',
'dienstgrad',
'sicherheitsfreigabe',
'wissensfreigabe',
'konfession',
'adresse',
'anmerkungen',
'personalarbeiter',
'standortleiter',
]) {
expect(schluessel).toContain(key)
}
})
it('ergibt genau das Raster des Formulars', async () => {
const { fields } = await felder()
const { photo, photoRows, rows } = dossierRows(fields)
expect(photo?.key).toBe('lichtbild')
expect(photoRows).toBe(4)
// Neben dem Lichtbild vier Zeilen zu je vier Spalten, danach fünf.
const struktur = rows.map((row, index) =>
row.map((field) => `${field.key}:${dossierSpan(field, index < photoRows)}`),
)
expect(struktur).toEqual([
['name:2', 'vorname:2'],
['alter:2', 'geschlecht:2'],
['groesse:4'],
['abteilung:2', 'dienstgrad:2'],
['sicherheitsfreigabe:3', 'wissensfreigabe:2'],
['konfession:2', 'adresse:3'],
['anmerkungen:5'],
['personalarbeiter:3', 'standortleiter:2'],
])
})
it('lässt die Datumsfelder der Unterschriften aus dem Raster heraus', async () => {
const { fields } = await felder()
const { rows } = dossierRows(fields)
const imRaster = rows.flat().map((f) => f.key)
// Sie stehen unter der jeweiligen Unterschrift, nicht in einer eigenen
// Zelle - bearbeitbar bleiben sie trotzdem.
expect(imRaster).not.toContain('personalarbeiter_datum')
expect(imRaster).not.toContain('standortleiter_datum')
expect(fields.map((f) => f.key)).toContain('personalarbeiter_datum')
})
it('hält die Klassifikation aus dem Raster heraus, sie gehört in den Balken', async () => {
const { fields } = await felder()
const { rows } = dossierRows(fields)
expect(rows.flat().map((f) => f.key)).not.toContain('foundation_klassifikation')
const feld = fields.find((f) => f.key === 'foundation_klassifikation')
expect(feld && isInputField(feld) && feld.slot).toBe('classbar')
})
it('kennt für jede Klassifikationsstufe eine Farbe', async () => {
const { fields } = await felder()
const feld = fields.find((f) => f.key === 'foundation_klassifikation')
const stufen = await db.foundationClearance.findMany({ orderBy: { level: 'asc' } })
// Sonst bliebe der Balken bei einer gültigen Auswahl grau.
const optionen = feld && isInputField(feld) ? (feld.options ?? []) : []
for (const option of optionen) {
expect(stufen.map((s) => String(s.level))).toContain(option)
}
for (const stufe of stufen) {
expect(stufe.colorHex).toMatch(/^#[0-9a-f]{6}$/i)
}
})
})