Files
Webklar-Kundenbereich/test/termineSchalter.test.js
T
ClaudeandClaude Sonnet 5.5 5c95dfc322 Terminplaner: Aufbewahrungs-Loeschung seitenweise (Grundlagen, verfallen/abgesagt/abgelehnt)
loeschKandidaten liest eine Seite (Standard 100, aelteste Bezugszeit zuerst, optional je Funktion)
ohne Gastfelder; die Frist steht in der Abfrage. arbeiteSeiten (Seite lesen, bearbeiten, neu lesen)
endet bei leerer Seite, am Deckel (config.termine.loeschDeckel, 2000 je Status und Lauf, Rest an den
Folgetagen, gezaehlt als gedeckelt) oder bei einer Seite ohne Fortschritt. verfallen, abgesagt und
abgelehnt laufen darueber, unter der Buchungssperre werden Status und Bezugszeit frisch geprueft.
taeglicherJob liefert gedeckelt getrennt vom Loeschzaehler. Neue Indizes idx_status_ends und
idx_status_updated auf termineBookings (scripts/termine-setup.mjs legt sie an).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 08:55:32 +00:00

157 lines
6.1 KiB
JavaScript

import { test, beforeEach, afterEach } from 'node:test'
import assert from 'node:assert/strict'
import { config } from '../server/config.js'
import { termineAus, termineFuerKunde, termineModus } from '../server/services/termine/schalter.js'
const TERMINE_ENV = [
'TERMINE_ENABLED',
'TERMINE_PILOT_EMAILS',
'TERMINE_FORM_MIN_SECONDS',
'TERMINE_MIN_ANTWORT_MS',
'APPWRITE_COLLECTION_TERMINE_CONFIG',
'APPWRITE_COLLECTION_TERMINE_BOOKINGS',
'APPWRITE_COLLECTION_TERMINE_CLAIMS',
'APPWRITE_COLLECTION_TERMINE_OUTBOX',
]
let original
beforeEach(() => {
original = { ...config.termine }
})
afterEach(() => {
Object.assign(config.termine, original)
})
/** Frische config.js-Instanz mit genau diesen Termine-Umgebungsvariablen (alle anderen entfernt). */
let freshCounter = 0
async function freshConfig(env = {}) {
const saved = Object.fromEntries(TERMINE_ENV.map((key) => [key, process.env[key]]))
for (const key of TERMINE_ENV) delete process.env[key]
Object.assign(process.env, env)
try {
freshCounter += 1
return (await import(`../server/config.js?termine-test=${freshCounter}`)).config
} finally {
for (const key of TERMINE_ENV) {
if (saved[key] === undefined) delete process.env[key]
else process.env[key] = saved[key]
}
}
}
test('Konfiguration: Vorgaben ohne Umgebungsvariablen', async () => {
const fresh = await freshConfig()
assert.deepEqual(fresh.termine, {
mode: 'off',
pilotEmails: [],
holdMinutes: 30,
zelleMin: 5,
mailsProStunde: 200,
loeschDeckel: 2000,
formMinSekunden: 3,
minAntwortMs: 300,
})
assert.equal(fresh.collections.termineConfig, 'termineConfig')
assert.equal(fresh.collections.termineBookings, 'termineBookings')
assert.equal(fresh.collections.termineClaims, 'termineClaims')
assert.equal(fresh.collections.termineOutbox, 'termineOutbox')
})
test('Konfiguration: Umgebungsvariablen werden gelesen und bereinigt', async () => {
const fresh = await freshConfig({
TERMINE_ENABLED: ' Pilot ',
TERMINE_PILOT_EMAILS: ' Kenso.Gri@Gmail.com, ,justin@webklar.com ',
TERMINE_FORM_MIN_SECONDS: '0',
TERMINE_MIN_ANTWORT_MS: '0',
APPWRITE_COLLECTION_TERMINE_CONFIG: 'tConfig',
APPWRITE_COLLECTION_TERMINE_BOOKINGS: 'tBookings',
APPWRITE_COLLECTION_TERMINE_CLAIMS: 'tClaims',
APPWRITE_COLLECTION_TERMINE_OUTBOX: 'tOutbox',
})
assert.equal(fresh.termine.mode, 'pilot')
assert.deepEqual(fresh.termine.pilotEmails, ['kenso.gri@gmail.com', 'justin@webklar.com'])
assert.equal(fresh.termine.formMinSekunden, 0)
assert.equal(fresh.termine.minAntwortMs, 0)
assert.deepEqual(
[fresh.collections.termineConfig, fresh.collections.termineBookings, fresh.collections.termineClaims, fresh.collections.termineOutbox],
['tConfig', 'tBookings', 'tClaims', 'tOutbox'],
)
})
test('Konfiguration: leerer oder unbekannter Schalter ist off, ungueltige Sekunden fallen auf 3', async () => {
for (const value of ['', ' ', 'banane', 'true', '1', 'ON ']) {
const fresh = await freshConfig({ TERMINE_ENABLED: value })
assert.equal(fresh.termine.mode, value.trim().toLowerCase() === 'on' ? 'on' : 'off', `TERMINE_ENABLED=${JSON.stringify(value)}`)
}
for (const value of ['', 'abc', '-1', 'NaN']) {
const fresh = await freshConfig({ TERMINE_FORM_MIN_SECONDS: value })
assert.equal(fresh.termine.formMinSekunden, 3, `TERMINE_FORM_MIN_SECONDS=${JSON.stringify(value)}`)
}
assert.equal((await freshConfig({ TERMINE_FORM_MIN_SECONDS: '7' })).termine.formMinSekunden, 7)
for (const value of ['', 'abc', '-1', 'NaN']) {
const fresh = await freshConfig({ TERMINE_MIN_ANTWORT_MS: value })
assert.equal(fresh.termine.minAntwortMs, 300, `TERMINE_MIN_ANTWORT_MS=${JSON.stringify(value)}`)
}
assert.equal((await freshConfig({ TERMINE_MIN_ANTWORT_MS: '750' })).termine.minAntwortMs, 750)
})
test('termineModus: leer und unbekannt sind off, pilot und on bleiben', () => {
for (const value of [undefined, null, '', 'banane', 'PILOT', 'true']) {
config.termine.mode = value
assert.equal(termineModus(), 'off', `mode=${JSON.stringify(value)}`)
assert.equal(termineAus(), true)
}
config.termine.mode = 'pilot'
assert.equal(termineModus(), 'pilot')
assert.equal(termineAus(), false)
config.termine.mode = 'on'
assert.equal(termineModus(), 'on')
assert.equal(termineAus(), false)
})
test('termineModus: Aenderung von config.termine.mode wirkt sofort', () => {
config.termine.mode = 'off'
assert.equal(termineModus(), 'off')
config.termine.mode = 'on'
assert.equal(termineModus(), 'on')
config.termine.mode = 'off'
assert.equal(termineAus(), true)
})
test('termineFuerKunde: off sperrt alle, auch mit Stern in der Liste', () => {
config.termine.mode = 'off'
config.termine.pilotEmails = ['*', 'kenso.gri@gmail.com']
assert.equal(termineFuerKunde('kenso.gri@gmail.com'), false)
assert.equal(termineFuerKunde('jemand@example.com'), false)
})
test('termineFuerKunde: pilot erlaubt nur Adressen der Liste, Schreibweise egal', () => {
config.termine.mode = 'pilot'
config.termine.pilotEmails = ['kenso.gri@gmail.com']
assert.equal(termineFuerKunde('KENSO.gri@gmail.com '), true)
assert.equal(termineFuerKunde('kenso.gri@gmail.com'), true)
assert.equal(termineFuerKunde('jemand@example.com'), false)
assert.equal(termineFuerKunde('kenso.gri@gmail.com.evil.de'), false)
})
test('termineFuerKunde: pilot mit Stern erlaubt alle, mit leerer Liste niemanden', () => {
config.termine.mode = 'pilot'
config.termine.pilotEmails = ['*']
assert.equal(termineFuerKunde('jemand@example.com'), true)
config.termine.pilotEmails = []
assert.equal(termineFuerKunde('kenso.gri@gmail.com'), false)
})
test('termineFuerKunde: pilot ohne E-Mail-Adresse ist false', () => {
config.termine.mode = 'pilot'
config.termine.pilotEmails = ['kenso.gri@gmail.com']
for (const email of [undefined, null, '', ' ']) assert.equal(termineFuerKunde(email), false)
})
test('termineFuerKunde: on gilt fuer alle ohne E-Mail-Filter', () => {
config.termine.mode = 'on'
config.termine.pilotEmails = ['kenso.gri@gmail.com']
assert.equal(termineFuerKunde('jemand@example.com'), true)
assert.equal(termineFuerKunde(undefined), true)
})