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
375 Vorkommen in 210 Dateien. Betrifft Kommentare, Oberflaechentexte und die README; an keiner Stelle Bedeutung, nur Zeichensetzung.
169 lines
5.8 KiB
TypeScript
169 lines
5.8 KiB
TypeScript
// @vitest-environment node
|
|
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
|
|
import { db } from '@/lib/db'
|
|
import { clearRecent, listRecent, noteOpened, RECENT_MAX } from '@/lib/recent/service'
|
|
import type { EffectivePermissions, Permission } from '@/lib/auth/permissions'
|
|
|
|
/**
|
|
* Die Sprungliste ist eine Bequemlichkeit - und genau deshalb der Ort, an dem
|
|
* eine Abkürzung besonders verlockend wäre: die Kennungen liegen ja schon da,
|
|
* warum sie nochmal prüfen? Weil eine vorgemerkte Kennung keine Berechtigung
|
|
* ist. Diese Datei prüft vor allem, dass die Liste nichts durchlässt.
|
|
*/
|
|
const url = process.env.DIRECT_DATABASE_URL ?? process.env.DATABASE_URL
|
|
const suite = url ? describe : describe.skip
|
|
|
|
const marke = `recent-${Date.now()}`
|
|
|
|
function perms(
|
|
userId: string,
|
|
clearanceLevel: number,
|
|
options: { isAdmin?: boolean; permissions?: Permission[] } = {},
|
|
): EffectivePermissions {
|
|
return {
|
|
userId,
|
|
clearanceLevel,
|
|
permissions: new Set<Permission>(options.permissions ?? []),
|
|
isAdmin: options.isAdmin ?? false,
|
|
hasMembership: true,
|
|
}
|
|
}
|
|
|
|
suite('Zuletzt geöffnet', () => {
|
|
const nutzer = { a: `${marke}-a`, b: `${marke}-b` }
|
|
let offenId = ''
|
|
let offenNummer = ''
|
|
let geheimId = ''
|
|
let personId = ''
|
|
|
|
beforeAll(async () => {
|
|
const vorlage = await db.documentTemplate.create({
|
|
data: { key: `${marke}-vorlage`, version: 1, name: 'Prüfvorlage', fields: [] },
|
|
})
|
|
for (const id of Object.values(nutzer)) {
|
|
await db.user.create({ data: { id, username: id, displayName: id } })
|
|
}
|
|
|
|
const gemeinsam = {
|
|
templateId: vorlage.id,
|
|
templateKey: vorlage.key,
|
|
createdById: nutzer.a,
|
|
}
|
|
const offen = await db.case.create({
|
|
data: {
|
|
...gemeinsam,
|
|
caseNumber: `Rez-2026-${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}`,
|
|
title: 'Offener Vorgang',
|
|
classification: 1,
|
|
status: 'OPEN',
|
|
},
|
|
})
|
|
const geheim = await db.case.create({
|
|
data: {
|
|
...gemeinsam,
|
|
caseNumber: `Rgh-2026-${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}`,
|
|
title: 'Streng vertraulich',
|
|
classification: 4,
|
|
status: 'OPEN',
|
|
},
|
|
})
|
|
const person = await db.personnelFile.create({
|
|
data: { displayName: `${marke}-Person`, classification: 1, createdById: nutzer.a },
|
|
})
|
|
|
|
offenId = offen.id
|
|
offenNummer = offen.caseNumber
|
|
geheimId = geheim.id
|
|
personId = person.id
|
|
})
|
|
|
|
afterAll(async () => {
|
|
await db.$disconnect()
|
|
})
|
|
|
|
it('merkt sich einen Sprung und zeigt ihn wieder', async () => {
|
|
await noteOpened(nutzer.a, 'CASE', offenId)
|
|
const liste = await listRecent(perms(nutzer.a, 1))
|
|
|
|
expect(liste.map((e) => e.targetId)).toContain(offenId)
|
|
expect(liste[0]?.href).toBe(`/faelle/${offenNummer}`)
|
|
expect(liste[0]?.label).toBe(offenNummer)
|
|
})
|
|
|
|
it('führt keinen Verlauf: zweimal öffnen bleibt eine Zeile', async () => {
|
|
await noteOpened(nutzer.a, 'CASE', offenId)
|
|
await noteOpened(nutzer.a, 'CASE', offenId)
|
|
|
|
const zeilen = await db.recentView.count({
|
|
where: { userId: nutzer.a, targetType: 'CASE', targetId: offenId },
|
|
})
|
|
expect(zeilen).toBe(1)
|
|
})
|
|
|
|
it('zeigt eine zu hoch eingestufte Akte nicht, auch wenn sie vorgemerkt ist', async () => {
|
|
// Der Fall, der zählt: die Kennung liegt in der Liste, die Freigabe fehlt.
|
|
// Etwa weil die Akte nach dem Öffnen hochgestuft wurde.
|
|
await noteOpened(nutzer.a, 'CASE', geheimId)
|
|
|
|
const hoch = await listRecent(perms(nutzer.a, 4))
|
|
expect(hoch.map((e) => e.targetId)).toContain(geheimId)
|
|
|
|
const niedrig = await listRecent(perms(nutzer.a, 1))
|
|
expect(niedrig.map((e) => e.targetId)).not.toContain(geheimId)
|
|
// Und keine Lücke, kein Platzhalter: die Zeile fehlt einfach.
|
|
expect(niedrig.every((e) => e.label.length > 0)).toBe(true)
|
|
})
|
|
|
|
it('zeigt Personalakten nur, wer sie überhaupt aufrufen darf', async () => {
|
|
await noteOpened(nutzer.a, 'PERSONNEL', personId)
|
|
|
|
const ohneRecht = await listRecent(perms(nutzer.a, 4))
|
|
expect(ohneRecht.map((e) => e.targetId)).not.toContain(personId)
|
|
|
|
const mitRecht = await listRecent(perms(nutzer.a, 4, { permissions: ['personnel.read'] }))
|
|
expect(mitRecht.map((e) => e.targetId)).toContain(personId)
|
|
})
|
|
|
|
it('zeigt niemandem die Liste eines anderen', async () => {
|
|
await noteOpened(nutzer.b, 'CASE', offenId)
|
|
|
|
// Nutzer a hat die Akte auch geöffnet - aber b bekommt seine eigene Zeile,
|
|
// und ein Administrator bekommt seine eigene, nicht die von b.
|
|
const admin = await listRecent(perms(`${marke}-admin`, 5, { isAdmin: true }))
|
|
expect(admin).toHaveLength(0)
|
|
})
|
|
|
|
it('behält nur die jüngsten Einträge', async () => {
|
|
const vorlage = await db.documentTemplate.findFirstOrThrow({
|
|
where: { key: `${marke}-vorlage` },
|
|
})
|
|
const viele = nutzer.b
|
|
for (let i = 0; i < RECENT_MAX + 3; i++) {
|
|
const akte = await db.case.create({
|
|
data: {
|
|
templateId: vorlage.id,
|
|
templateKey: vorlage.key,
|
|
createdById: viele,
|
|
caseNumber: `Rvi-${Date.now()}-${i}`,
|
|
title: `Vorgang ${i}`,
|
|
classification: 1,
|
|
status: 'OPEN',
|
|
},
|
|
})
|
|
await noteOpened(viele, 'CASE', akte.id)
|
|
}
|
|
|
|
const zeilen = await db.recentView.count({ where: { userId: viele } })
|
|
expect(zeilen).toBeLessThanOrEqual(RECENT_MAX)
|
|
// Die zuerst geöffnete Akte ist hinten herausgefallen.
|
|
const liste = await listRecent(perms(viele, 1), RECENT_MAX)
|
|
expect(liste.map((e) => e.targetId)).not.toContain(offenId)
|
|
})
|
|
|
|
it('lässt sich leeren', async () => {
|
|
await noteOpened(nutzer.a, 'CASE', offenId)
|
|
expect(await clearRecent(nutzer.a)).toBeGreaterThan(0)
|
|
expect(await listRecent(perms(nutzer.a, 5, { isAdmin: true }))).toHaveLength(0)
|
|
})
|
|
})
|