Terminplaner: Schalter, Konfiguration, Schema
Schalter TERMINE_ENABLED (off|pilot|on) mit TERMINE_PILOT_EMAILS, config.termine und die vier Collection-IDs, Schema der Termine-Collections als reine Daten (server/services/termine/schema.js), Setup-Skript scripts/termine-setup.mjs mit --check und schemaKeys() fuer den Appwrite-Nachbau der Tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f63165c158
commit
334dc1e669
7 files changed
+714
-1
No files matched your search
@@ -0,0 +1,146 @@
|
||||
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',
|
||||
'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,
|
||||
formMinSekunden: 3,
|
||||
})
|
||||
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',
|
||||
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.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)
|
||||
})
|
||||
|
||||
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)
|
||||
})
|
||||
Reference in new issue
Block a user