import { test } from 'node:test' import assert from 'node:assert/strict' import { h } from '../public/termine-dom.js' import { initZeiten } from '../public/zeiten.js' import { zeitenStatusKarte } from '../public/zeiten-bestellen.js' import { KEIN_PREIS, einschaltenAttrappe, mitDom, routen } from './support/modulAbo.js' // Öffnungszeiten live im Abo-Modell (P4 Task 7): Einschalten über den Ablauf von P3, kein Behalten-Weg, Abo-Ende und Abschaltung ohne Preis // (Texte Z2, Z3, E5). Ohne modell === 'abo' bleiben Bestellseite, „Für 30 € behalten“ und „Bestellt am“. const EDITOR = { state: 'active', daten: null, version: 0, kundenansicht: false, vorschau: null, feiertage: [], googleText: '' } // Antwort von GET /api/zeiten/p1 const feature = (state, extra = {}) => ({ state, siteKey: null, ticketWoid: null, orderedAt: null, activatedAt: null, invoiceUrl: null, disabledReason: null, disabledAt: null, loeschungAm: null, unlockedBy: state === 'off' ? null : 'abo', aboEndeAt: null, einbau: null, ...extra, }) const liste = (modell, state = 'off', extra = {}, angebot = {}) => ({ body: { ...(modell ? { modell } : {}), projects: [{ projectId: 'p1', projectName: 'Website p1', liveUrl: '', features: { news: { state: 'off' }, zeiten: feature(state, extra) }, zeitenStatus: null, zeitenLeer: false }], features: { zeiten: { priceLabel: '30 €', consent: { version: 'v', knopf: 'Zahlungspflichtig bestellen · 30 €', items: [] }, leistungsbeschreibung: { version: '2026-10-05', url: '/vertragsunterlagen/zeiten-leistungsbeschreibung.html' }, }, }, ustHinweis: 'ohne Umsatzsteuer gemäß § 19 UStG', zeiten: { verfuegbar: true, inklusive: true, grund: null, preis: '30 €', einschalten: { consent: { version: 'v', knopf: 'Einschalten', items: [] }, leistungsbeschreibung: { version: '2026-10-05', url: '/vertragsunterlagen/zeiten-leistungsbeschreibung.html' } }, belehrung: 'Belehrung', ...angebot, }, }, }) async function oeffne(fx, antwort, { einschalten, dataset = {} } = {}) { routen(fx, { 'GET /api/funktionen': antwort, 'GET /api/zeiten/p1': { body: EDITOR } }) const root = h('div') document.body.append(root) Object.assign(root.dataset, dataset) await initZeiten(root, { projectId: 'p1', einschalten }) await fx.ruhe() return root } const ALT_ENDE = { aboEndeAt: '2026-09-01T00:00:00.000Z' } const KEIN_ABO = { inklusive: false, grund: 'kein_abo' } test('Abo, off: Einschalt-Seite mit key zeiten, ohne Haken, Preis und Behalten; nach onFertig die Danke-Zeile', mitDom(async (fx) => { const a = einschaltenAttrappe() let n = 0 const root = await oeffne(fx, () => (n === 0 ? liste('abo') : liste('abo', 'setup')), { einschalten: a.fn }) assert.deepEqual([a.aufrufe[0].key, a.aufrufe[0].projectId, a.aufrufe[0].viewAs], ['zeiten', 'p1', false]) assert.equal(fx.alle(root, 'input[type="checkbox"]').length, 0) assert.ok(fx.finde(root, '[data-aktion="behalten"], [data-aktion="bestellen"], [data-aktion="einschalten"]') === null) assert.doesNotMatch(fx.text(root), KEIN_PREIS) n = 1 a.fertig(0) await fx.ruhe() assert.match(fx.text(fx.finde(root, '.zt-status')), /Öffnungszeiten live ist eingeschaltet\./) })) test('Abo, off ohne Funktion einschalten: Fehlerkarte E4', mitDom(async (fx) => { const root = await oeffne(fx, liste('abo')) assert.match(fx.text(root), /Das Einschalten ist gerade nicht verfügbar\. Bitte lade die Seite neu oder schreib uns im Chat\./) })) test('Abo: Abo-Ende in active nennt die Frist (Z2) und „Eingeschaltet am“, ohne Preis und ohne Behalten-Knopf', mitDom(async (fx) => { const karte = zeitenStatusKarte({ projekt: { projectId: 'p1', zeitenLeer: false }, feature: { state: 'active', orderedAt: '2026-08-01T10:00:00.000Z', ...ALT_ENDE }, angebot: { ...KEIN_ABO, preis: '30 €' }, modell: 'abo' }, {}) assert.match(fx.text(karte), /Dein Wartungs-Abo ist beendet\. Öffnungszeiten live läuft noch bis 01\.10\.2026 und schaltet sich dann ab\./) assert.match(fx.text(karte), /Eingeschaltet am\s*01\.08\.2026/) assert.ok(fx.finde(karte, '[data-aktion="behalten"]') === null) assert.doesNotMatch(fx.text(karte), KEIN_PREIS) })) test('Abo: abgeschaltet mit Daten (Z3), ohne Behalten-Knopf', mitDom(async (fx) => { const karte = zeitenStatusKarte({ projekt: { projectId: 'p1', zeitenLeer: false }, feature: { state: 'disabled', disabledReason: 'abo_ende', loeschungAm: '2099-12-31' }, angebot: { ...KEIN_ABO, preis: '30 €' }, modell: 'abo' }, {}) assert.match(fx.text(karte), /Deine Eingaben bleiben bis 31\.12\.2099 gespeichert\. Mit einem neuen Wartungs-Abo schaltet sich Öffnungszeiten live wieder ein\./) assert.ok(fx.finde(karte, '[data-aktion="behalten"]') === null) assert.doesNotMatch(fx.text(karte), KEIN_PREIS) const ohneDatum = zeitenStatusKarte({ projekt: { projectId: 'p1', zeitenLeer: false }, feature: { state: 'disabled', disabledReason: 'abo_ende' }, angebot: { ...KEIN_ABO, preis: '30 €' }, modell: 'abo' }, {}) assert.match(fx.text(ohneDatum), /Deine Eingaben bleiben gespeichert\. Mit einem neuen Wartungs-Abo schaltet sich Öffnungszeiten live wieder ein\./) })) test('wunschWeg „behalten“: im Abo-Modell ohne Wirkung, ohne modell die Behalten-Seite und der Knopf „Für 30 € behalten“', mitDom(async (fx) => { const wunsch = { dataset: { wunschWeg: 'behalten' } } const abo = await oeffne(fx, liste('abo', 'active', ALT_ENDE, KEIN_ABO), wunsch) assert.ok(fx.finde(abo, '[data-variante="behalten"]') === null) assert.ok(fx.finde(abo, '[data-aktion="behalten"]') === null) assert.ok(fx.finde(abo, '.zt-status')) assert.equal(abo.dataset.wunschWeg, undefined) const alt = await oeffne(fx, liste(undefined, 'active', ALT_ENDE, KEIN_ABO), wunsch) assert.ok(fx.finde(alt, '[data-variante="behalten"]')) const karte = zeitenStatusKarte({ projekt: { projectId: 'p1', zeitenLeer: false }, feature: { state: 'active', ...ALT_ENDE }, angebot: { ...KEIN_ABO, preis: '30 €' } }, {}) assert.equal(fx.text(fx.finde(karte, '[data-aktion="behalten"]')), 'Für 30 € behalten') })) test('Ohne modell (fehlt, „Abo“, „abo “): Bestellseite wie bisher, „Bestellt am“, der Ablauf wird nie gerufen', mitDom(async (fx) => { for (const modell of [undefined, 'Abo', 'abo ']) { const a = einschaltenAttrappe() const bestellen = await oeffne(fx, liste(modell, 'off', {}, KEIN_ABO), { einschalten: a.fn }) assert.ok(fx.finde(bestellen, '[data-aktion="bestellen"]'), String(modell)) assert.equal(a.aufrufe.length, 0) const karte = zeitenStatusKarte({ projekt: { projectId: 'p1', zeitenLeer: false }, feature: { state: 'active', orderedAt: '2026-08-01T10:00:00.000Z' }, angebot: { inklusive: true }, modell }, {}) assert.match(fx.text(karte), /Bestellt am\s*01\.08\.2026/) } }))