Datenbank- und Worker-Tests auf den Chat in der Akte nachgezogen

Die Regel „eine Nachricht gehört zu genau einem Ort" wird jetzt stärker
geprüft als vorher: zwei Orte, kein Ort und genau einer. Vorher hing sie
allein an der Anwendung, jetzt an einem CHECK.

Der Worker-Test prüft ausdrücklich, dass die Meldung den Namen der Person
nicht nennt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Harlekin
2026-09-03 15:19:04 +02:00
co-authored by Claude Opus 5
parent 5f9f5d99fb
commit e9f7df8397
2 changed files with 46 additions and 13 deletions
+34 -9
View File
@@ -28,7 +28,7 @@ suite('Datenbankregeln', () => {
}) })
const fall = await db.case.create({ const fall = await db.case.create({
data: { data: {
caseNumber: `AfiS-9999-${String(Date.now()).slice(-4)}`, caseNumber: `AfiS-9999-${Date.now().toString(36)}`,
title: 'Prüffall', title: 'Prüffall',
templateId: template.id, templateId: template.id,
templateKey: template.key, templateKey: template.key,
@@ -131,27 +131,52 @@ suite('Datenbankregeln', () => {
).rejects.toThrow() ).rejects.toThrow()
}) })
it('lässt eine Chatnachricht nicht zugleich an Akte und Kanal hängen', async () => { it('lässt eine Chatnachricht nur an genau einem Ort hängen', async () => {
const kanal = await db.channel.create({ const person = await db.personnelFile.create({
data: { key: `${marke}-kanal`, name: 'Prüfkanal', createdById: `${marke}-nutzer` }, data: { displayName: `${marke}-person`, classification: 1 },
}) })
// Zwei Orte: geht nicht.
await expect( await expect(
db.chatMessage.create({ db.chatMessage.create({
data: { data: {
id: `${marke}-nachricht`, id: `${marke}-nachricht-zwei`,
caseId, caseId,
channelId: kanal.id, personnelFileId: person.id,
authorId: `${marke}-nutzer`,
body: 'gehört an zwei Stellen',
},
}),
).rejects.toThrow()
// Gar kein Ort: geht auch nicht. Eine Nachricht ohne Akte wäre ein
// Gespräch ohne Vorgang, und genau das soll es nicht mehr geben.
await expect(
db.chatMessage.create({
data: {
id: `${marke}-nachricht-null`,
authorId: `${marke}-nutzer`, authorId: `${marke}-nutzer`,
body: 'gehört nirgends hin', body: 'gehört nirgends hin',
}, },
}), }),
).rejects.toThrow() ).rejects.toThrow()
// Einer: geht.
const gut = await db.chatMessage.create({
data: {
id: `${marke}-nachricht-eins`,
personnelFileId: person.id,
authorId: `${marke}-nutzer`,
body: 'gehört zur Personalakte',
},
})
expect(gut.personnelFileId).toBe(person.id)
}) })
it('lässt ein Dokument nicht löschen', async () => { it('lässt ein Dokument nicht löschen', async () => {
const doc = await db.document.create({ const doc = await db.document.create({
data: { data: {
documentNumber: `PRF-9999-${String(Date.now()).slice(-6)}`, documentNumber: `PRF-9999-${Date.now().toString(36)}`,
title: 'Prüfdokument', title: 'Prüfdokument',
templateId: (await db.documentTemplate.findFirstOrThrow({ templateId: (await db.documentTemplate.findFirstOrThrow({
where: { key: `${marke}-vorlage` }, where: { key: `${marke}-vorlage` },
@@ -177,7 +202,7 @@ suite('Datenbankregeln', () => {
await expect( await expect(
db.document.create({ db.document.create({
data: { data: {
documentNumber: `PRF-9998-${String(Date.now()).slice(-6)}`, documentNumber: `PRF-9998-${Date.now().toString(36)}`,
title: 'Zwei Besitzer', title: 'Zwei Besitzer',
templateId: (await db.documentTemplate.findFirstOrThrow({ templateId: (await db.documentTemplate.findFirstOrThrow({
where: { key: `${marke}-vorlage` }, where: { key: `${marke}-vorlage` },
@@ -195,7 +220,7 @@ suite('Datenbankregeln', () => {
it('lässt den Besitzer eines Dokuments nicht nachträglich wechseln', async () => { it('lässt den Besitzer eines Dokuments nicht nachträglich wechseln', async () => {
const doc = await db.document.create({ const doc = await db.document.create({
data: { data: {
documentNumber: `PRF-9997-${String(Date.now()).slice(-6)}`, documentNumber: `PRF-9997-${Date.now().toString(36)}`,
title: 'Unverrückbar', title: 'Unverrückbar',
templateId: (await db.documentTemplate.findFirstOrThrow({ templateId: (await db.documentTemplate.findFirstOrThrow({
where: { key: `${marke}-vorlage` }, where: { key: `${marke}-vorlage` },
+12 -4
View File
@@ -28,10 +28,18 @@ describe('Text der Benachrichtigung', () => {
expect(mit).toContain('Korruptionsverdacht') expect(mit).toContain('Korruptionsverdacht')
}) })
it('kann eine Erwähnung in einem Kanal melden', () => { it('meldet eine Erwähnung in einer Personalakte ohne den Namen der Person', () => {
expect( const text = composeMessage(
composeMessage('chat.mention', { channelKey: 'leitung', actorName: 'Vogel' }, url), 'chat.mention',
).toBe('Vogel hat dich in #leitung erwähnt · https://afis.example.de/kanaele/leitung') { personnelFileId: '0192abc', actorName: 'Vogel' },
url,
)
// Dass es zu jemandem eine Personalakte gibt, ist selbst eine Auskunft.
// Deshalb steht in der Meldung nur der Link, kein Name.
expect(text).toBe(
'Vogel hat dich im Chat einer Personalakte erwähnt · https://afis.example.de/personalakten/0192abc',
)
}) })
it('schweigt, wenn nichts Verwertbares mitkam', () => { it('schweigt, wenn nichts Verwertbares mitkam', () => {