Öffnungszeiten: Schalter, Collections und Felder
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>
This commit is contained in:
1 parent
385f768d76
commit
4b4cd1058f
7 files changed
+649
-3
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 { 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'])
|
||||
})
|
||||
Reference in new issue
Block a user