Files
Webklar-Kundenbereich/test/termineSchalter.test.js
T
ClaudeandClaude Sonnet 5.5 36b94c3035 Terminplaner: Mail-Warteschlange begrenzt und nach Vorrang geordnet
verarbeite liest nicht mehr alle wartenden Eintraege, sondern je Klasse
(vorrang, normal, nachrangig) eine begrenzte Liste (config.termine.mailListe,
Standard 100) mit select und orderAsc(naechsterVersuch). Bei Pause oder
leerem Gesamtbudget endet der Lauf ohne Abfrage, bei erreichter Reserve
entfaellt die nachrangige Klasse. Funktionen mit ausgeschoepftem Kontingent
kommen in eine Ausschlussliste (hoechstens 90 Werte); hoechstens vier weitere
Runden je Klasse, damit keine Funktion hinter einer vollen verhungert.

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

162 lines
6.2 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,
mailsProFunktion: 40,
mailsReserve: 0.25,
mailListe: 100,
loeschDeckel: 2000,
loeschDeckelGesamt: 20000,
zellenDeckel: 5000,
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)
})