ZEITEN_ENABLED/ZEITEN_PILOT_EMAILS/ZEITEN_KEIN_NEUBAU als config.zeiten (neben config.termine), zeitenSetup (30 € einmalig), Collection-IDs oeffnungszeiten und zeitenErinnerungen, Schema der beiden Collections plus fünf neue portalFeatures-Felder, scripts/zeiten-setup.mjs (idempotent, --check), schemaKeys kennt die neuen Collections und Felder. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
147 lines
5.6 KiB
JavaScript
147 lines
5.6 KiB
JavaScript
import { test, beforeEach, afterEach } from 'node:test'
|
||
import assert from 'node:assert/strict'
|
||
import { config } from '../server/config.js'
|
||
import { zeitenAus, zeitenFuerKunde, zeitenModus } from '../server/services/zeiten/schalter.js'
|
||
|
||
const ZEITEN_ENV = [
|
||
'ZEITEN_ENABLED',
|
||
'ZEITEN_PILOT_EMAILS',
|
||
'ZEITEN_KEIN_NEUBAU',
|
||
'APPWRITE_COLLECTION_OEFFNUNGSZEITEN',
|
||
'APPWRITE_COLLECTION_ZEITEN_ERINNERUNGEN',
|
||
]
|
||
|
||
let original
|
||
beforeEach(() => {
|
||
original = { ...config.zeiten }
|
||
})
|
||
afterEach(() => {
|
||
Object.assign(config.zeiten, original)
|
||
})
|
||
|
||
/** Frische config.js-Instanz mit genau diesen Zeiten-Umgebungsvariablen (alle anderen entfernt). */
|
||
let freshCounter = 0
|
||
async function freshConfig(env = {}) {
|
||
const saved = Object.fromEntries(ZEITEN_ENV.map((key) => [key, process.env[key]]))
|
||
for (const key of ZEITEN_ENV) delete process.env[key]
|
||
Object.assign(process.env, env)
|
||
try {
|
||
freshCounter += 1
|
||
return (await import(`../server/config.js?zeiten-test=${freshCounter}`)).config
|
||
} finally {
|
||
for (const key of ZEITEN_ENV) {
|
||
if (saved[key] === undefined) delete process.env[key]
|
||
else process.env[key] = saved[key]
|
||
}
|
||
}
|
||
}
|
||
|
||
test('Vorgabe ist aus', async () => {
|
||
const fresh = await freshConfig()
|
||
assert.deepEqual(fresh.zeiten, { mode: 'off', pilotEmails: [], keinNeubau: ['emmas-schatzkiste'] })
|
||
// ZEITEN_ENABLED leer ⇒ aus; der Schalter liest config.zeiten bei jedem Aufruf
|
||
config.zeiten.mode = fresh.zeiten.mode
|
||
assert.equal(zeitenModus(), 'off')
|
||
assert.equal(zeitenAus(), true)
|
||
assert.equal(zeitenFuerKunde('kenso.gri@gmail.com'), false)
|
||
})
|
||
|
||
test('Konfiguration: leerer oder unbekannter Schalter ist off, Umgebungsvariablen werden bereinigt', async () => {
|
||
for (const value of ['', ' ', 'banane', 'true', '1']) {
|
||
assert.equal((await freshConfig({ ZEITEN_ENABLED: value })).zeiten.mode, 'off', `ZEITEN_ENABLED=${JSON.stringify(value)}`)
|
||
}
|
||
assert.equal((await freshConfig({ ZEITEN_ENABLED: ' ON ' })).zeiten.mode, 'on')
|
||
const fresh = await freshConfig({
|
||
ZEITEN_ENABLED: ' Pilot ',
|
||
ZEITEN_PILOT_EMAILS: ' Kenso.Gri@Gmail.com, ,justin@webklar.com ',
|
||
})
|
||
assert.equal(fresh.zeiten.mode, 'pilot')
|
||
assert.deepEqual(fresh.zeiten.pilotEmails, ['kenso.gri@gmail.com', 'justin@webklar.com'])
|
||
})
|
||
|
||
test('zeitenModus: leer und unbekannt sind off, pilot und on bleiben', () => {
|
||
for (const value of [undefined, null, '', 'banane', 'PILOT', 'true']) {
|
||
config.zeiten.mode = value
|
||
assert.equal(zeitenModus(), 'off', `mode=${JSON.stringify(value)}`)
|
||
assert.equal(zeitenAus(), true)
|
||
}
|
||
config.zeiten.mode = 'pilot'
|
||
assert.equal(zeitenModus(), 'pilot')
|
||
assert.equal(zeitenAus(), false)
|
||
config.zeiten.mode = 'on'
|
||
assert.equal(zeitenModus(), 'on')
|
||
assert.equal(zeitenAus(), false)
|
||
})
|
||
|
||
test('off sperrt alle, auch mit Stern in der Liste', () => {
|
||
config.zeiten.mode = 'off'
|
||
config.zeiten.pilotEmails = ['*', 'kenso.gri@gmail.com']
|
||
assert.equal(zeitenFuerKunde('kenso.gri@gmail.com'), false)
|
||
assert.equal(zeitenFuerKunde('jemand@example.com'), false)
|
||
})
|
||
|
||
test('pilot gilt nur für die Pilotliste', () => {
|
||
config.zeiten.mode = 'pilot'
|
||
config.zeiten.pilotEmails = ['a@b.de']
|
||
assert.equal(zeitenFuerKunde('A@b.de'), true)
|
||
assert.equal(zeitenFuerKunde(' a@b.de '), true)
|
||
assert.equal(zeitenFuerKunde('x@y.de'), false)
|
||
assert.equal(zeitenFuerKunde('a@b.de.evil.de'), false)
|
||
// Stern = alle, leere Liste = niemand, ohne Adresse = niemand
|
||
config.zeiten.pilotEmails = ['*']
|
||
assert.equal(zeitenFuerKunde('x@y.de'), true)
|
||
config.zeiten.pilotEmails = []
|
||
assert.equal(zeitenFuerKunde('a@b.de'), false)
|
||
config.zeiten.pilotEmails = ['a@b.de']
|
||
for (const email of [undefined, null, '', ' ']) assert.equal(zeitenFuerKunde(email), false)
|
||
})
|
||
|
||
test('on gilt für alle', () => {
|
||
config.zeiten.mode = 'on'
|
||
config.zeiten.pilotEmails = ['a@b.de']
|
||
assert.equal(zeitenFuerKunde('x@y.de'), true)
|
||
assert.equal(zeitenFuerKunde(undefined), true)
|
||
})
|
||
|
||
test('keinNeubau kommt aus ZEITEN_KEIN_NEUBAU, Vorgabe emmas-schatzkiste', async () => {
|
||
assert.deepEqual((await freshConfig()).zeiten.keinNeubau, ['emmas-schatzkiste'])
|
||
assert.deepEqual((await freshConfig({ ZEITEN_KEIN_NEUBAU: '' })).zeiten.keinNeubau, ['emmas-schatzkiste'])
|
||
assert.deepEqual(
|
||
(await freshConfig({ ZEITEN_KEIN_NEUBAU: ' Emmas-Schatzkiste, , Andere-Site ' })).zeiten.keinNeubau,
|
||
['emmas-schatzkiste', 'andere-site'],
|
||
)
|
||
})
|
||
|
||
test('zeiten steht neben config.termine, nicht darin', async () => {
|
||
const fresh = await freshConfig()
|
||
assert.equal('keinNeubau' in fresh.termine, false)
|
||
assert.equal('zeiten' in fresh.termine, false)
|
||
assert.notEqual(fresh.zeiten, fresh.termine)
|
||
})
|
||
|
||
test('zeitenSetup: 3000 Cent einmalig', async () => {
|
||
const fresh = await freshConfig()
|
||
assert.deepEqual(fresh.zeitenSetup, {
|
||
key: 'zeitenSetup',
|
||
name: 'Öffnungszeiten live – Einrichtung',
|
||
amountCents: 3000,
|
||
lookupKey: 'webklar_zeiten_einrichtung_3000',
|
||
oneTime: true,
|
||
priceNickname: 'Öffnungszeiten-Einrichtung 30 €',
|
||
})
|
||
assert.equal(config.zeitenSetup.amountCents, 3000)
|
||
assert.equal(config.zeitenSetup.oneTime, true)
|
||
assert.equal(config.zeitenSetup.lookupKey, 'webklar_zeiten_einrichtung_3000')
|
||
})
|
||
|
||
test('Konfiguration: Collection-IDs der Zeiten-Collections', async () => {
|
||
const fresh = await freshConfig()
|
||
assert.equal(fresh.collections.oeffnungszeiten, 'oeffnungszeiten')
|
||
assert.equal(fresh.collections.zeitenErinnerungen, 'zeitenErinnerungen')
|
||
const anders = await freshConfig({
|
||
APPWRITE_COLLECTION_OEFFNUNGSZEITEN: 'zDaten',
|
||
APPWRITE_COLLECTION_ZEITEN_ERINNERUNGEN: 'zMerker',
|
||
})
|
||
assert.deepEqual([anders.collections.oeffnungszeiten, anders.collections.zeitenErinnerungen], ['zDaten', 'zMerker'])
|
||
})
|