Funktionen: Vertragsunterlagen als K15-Anhang, Belehrung vor dem Bestellknopf

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-05 03:20:56 +00:00
1 parent 03bdeb4461
commit 2c059cb3d6
11 files changed
+574 -39

No files matched your search

+78 -3
View File
@@ -1,6 +1,8 @@
import { test, after } from 'node:test'
import { test, after, mock } from 'node:test'
import assert from 'node:assert/strict'
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
import { closeSync, copyFileSync, mkdirSync, mkdtempSync, openSync, readFileSync, rmSync, writeFileSync, writeSync } from 'node:fs'
import fsp from 'node:fs/promises'
import { syncBuiltinESMExports } from 'node:module'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { Router } from 'express'
@@ -9,7 +11,7 @@ import { useTestEnv } from './support/testEnv.js'
useTestEnv({ appwriteUrl: 'http://127.0.0.1:1', stripeUrl: 'http://127.0.0.1:1' })
const { config } = await import('../server/config.js')
const { startTestApp } = await import('./support/testApp.js')
const { legalPaths, legalPdfFiles, legalPdfAttachments, featureLegalAttachments, featureLegalReady, legalRouter } = await import(
const { legalPaths, legalPdfFiles, legalPdfAttachments, featureLegalAttachments, featureLegalReady, legalRouter, setLegalDirForTests } = await import(
'../server/services/legalDocs.js'
)
const analyse = await import('../server/services/analyseLegal.js')
@@ -125,6 +127,79 @@ test('featureLegalAttachments("termine") liest die Fassung aus config.termine.av
})
})
// R114 (Task F8): featureLegalReady läuft bei jeder Bestellung (Stufe 5b des Checkouts) und prüft je PDF nur stat (Größe > 0) und die
// ersten fünf Bytes "%PDF-", nie den ganzen Inhalt. Die Dateien liegen für den Test in einem Verzeichnis mit Kopien.
test('featureLegalReady("termine"): je PDF stat und "%PDF-", nie den ganzen Inhalt lesen; jeder Mangel und jeder Fehler ergibt false, nie einen Wurf', async () => {
const kopien = mkdtempSync(join(tmpdir(), 'legal-ready-'))
mkdirSync(join(kopien, 'rechtliches'))
// Quellen: die ausgelieferten Dateien (vor dem Tausch des Verzeichnisses ermittelt)
const echteHtml = legalPaths('termine', V)
const echtePdf = Object.fromEntries(Object.entries(legalPdfFiles('termine', V)).map(([doc, f]) => [doc, f.path]))
const bereit = () => {
for (const adresse of Object.values(echteHtml)) copyFileSync(root(`public${adresse}`), join(kopien, adresse))
for (const pfad of Object.values(echtePdf)) copyFileSync(pfad, join(kopien, 'rechtliches', pfad.split('/').at(-1)))
}
const pdfPfad = (doc) => join(kopien, 'rechtliches', echtePdf[doc].split('/').at(-1))
const htmlPfad = (doc) => join(kopien, echteHtml[doc])
const lesen = mock.method(fsp, 'readFile')
syncBuiltinESMExports()
try {
setLegalDirForTests(kopien)
bereit()
assert.equal(await featureLegalReady('termine'), true)
assert.equal(lesen.mock.callCount(), 0, 'readFile wird nicht aufgerufen')
// ein riesiges PDF mit gültigem Kopf (nur Loch im Dateisystem): bereit, ohne es zu lesen
const gross = openSync(pdfPfad('lb'), 'w')
writeSync(gross, '%PDF-1.4\n')
closeSync(gross)
await fsp.truncate(pdfPfad('lb'), 512 * 1024 * 1024)
assert.equal(await featureLegalReady('termine'), true)
assert.equal(lesen.mock.callCount(), 0, 'auch ein 512-MB-PDF wird nicht gelesen')
bereit()
// Mängel je Datei: fehlend, leer, falscher Kopf, zu kurz, Verzeichnis statt Datei
for (const doc of ['lb', 'avv', 'widerruf']) {
const pfad = pdfPfad(doc)
rmSync(pfad)
assert.equal(await featureLegalReady('termine'), false, `${doc}: PDF fehlt`)
writeFileSync(pfad, '')
assert.equal(await featureLegalReady('termine'), false, `${doc}: PDF leer`)
writeFileSync(pfad, '<html>kein PDF</html>')
assert.equal(await featureLegalReady('termine'), false, `${doc}: kein %PDF-`)
writeFileSync(pfad, '%PDF')
assert.equal(await featureLegalReady('termine'), false, `${doc}: zu kurz`)
rmSync(pfad)
mkdirSync(pfad)
assert.equal(await featureLegalReady('termine'), false, `${doc}: Verzeichnis statt Datei`)
rmSync(pfad, { recursive: true })
bereit()
assert.equal(await featureLegalReady('termine'), true, `${doc}: wieder bereit`)
// die HTML-Seite fehlt
rmSync(htmlPfad(doc))
assert.equal(await featureLegalReady('termine'), false, `${doc}: HTML fehlt`)
bereit()
}
assert.equal(lesen.mock.callCount(), 0, 'nie readFile')
// ohne Verzeichnis, mit unbekannter Funktion und mit unbekannter Fassung: false statt Wurf
await mitFassung('1999-01-01', async () => assert.equal(await featureLegalReady('termine'), false))
assert.equal(await featureLegalReady('gibtsnicht'), false)
setLegalDirForTests(join(kopien, 'gibtsnicht'))
assert.equal(await featureLegalReady('termine'), false)
// die Anhänge der Mail lesen dagegen die ganzen Dateien (legalPdfAttachments)
setLegalDirForTests(kopien)
bereit()
assert.equal((await featureLegalAttachments('termine')).length, 3)
assert.ok(lesen.mock.callCount() >= 3)
} finally {
setLegalDirForTests(null)
mock.restoreAll()
syncBuiltinESMExports()
rmSync(kopien, { recursive: true, force: true })
}
assert.equal(await featureLegalReady('termine'), true, 'mit den ausgelieferten Dateien bereit')
})
test('config.termine.avvVersion: Datumsmuster, nach der Altfassung der Gästetexte, echter Tag', () => {
assert.match(config.termine.avvVersion, /^\d{4}-\d{2}-\d{2}$/)
assert.ok(config.termine.avvVersion > ALT, `${config.termine.avvVersion} liegt nicht nach ${ALT}`)