Files
ClaudeandClaude Opus 5.5 4b4cd1058f Ö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>
2026-10-04 23:25:37 +00:00

147 lines
5.6 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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'])
})