import { test } from 'node:test' import assert from 'node:assert/strict' const { config } = await import('../server/config.js') const { WORTLAUT_V6, FUNKTIONEN_FASSUNG_V6, FUNKTIONEN_UNTERLAGEN_V6, mitFassung } = await import('../server/services/products.js') test('Linkzeilen: Wortlaut, Platzhalter wird gefüllt', () => { assert.equal(mitFassung(WORTLAUT_V6.linkzeile.bestellen, '2026-10-16-v6'), 'Es gelten die Vertragsbedingungen mit Leistungsbeschreibung, Auftragsverarbeitung und Widerrufsbelehrung (Fassung 2026-10-16-v6). Alles kommt danach auch als PDF per Mail.') assert.equal(mitFassung(WORTLAUT_V6.linkzeile.einschaltenMitAvv, '2026-10-16'), 'Es gelten Leistungsbeschreibung und Auftragsverarbeitung (Fassung 2026-10-16).') assert.equal(mitFassung(WORTLAUT_V6.linkzeile.einschaltenOhneAvv, '2026-10-16'), 'Es gilt die Leistungsbeschreibung (Fassung 2026-10-16).') assert.throws(() => mitFassung(WORTLAUT_V6.linkzeile.bestellen, ''), /Fassung/) assert.throws(() => mitFassung('ohne Platzhalter', '2026-10-16'), /Platzhalter/) }) test('Häkchen beginn: Wortlaut je Fall (nur privat in der Frist)', () => { assert.deepEqual(WORTLAUT_V6.beginn, { abo: 'Bitte beginnt sofort mit dem Abo. Mir ist klar: Widerrufe ich innerhalb von 14 Tagen, zahle ich den bis dahin erbrachten Teil.', wechsel: 'Bitte beginnt sofort mit dem Wechsel. Mir ist klar: Widerrufe ich innerhalb von 14 Tagen, zahle ich den bis dahin erbrachten Teil.', einrichtung: 'Bitte beginnt sofort mit der Einrichtung. Mir ist klar: Mit der vollständigen Einrichtung erlischt mein Widerrufsrecht, und wenn ich vorher widerrufe, zahle ich den bis dahin erbrachten Teil.', }) }) test('Pflichten aus den alten Häkchen verantwortung, stripe, gesundheit', () => { assert.deepEqual(WORTLAUT_V6.hinweis, { shop: 'Du verkaufst in eigenem Namen und bist für deine Produkte, Preise und Rechtstexte verantwortlich. Die Zahlungen deiner Käufer laufen über dein eigenes Stripe-Konto.', unterkunft: 'Du vermietest in eigenem Namen und bist für Preise, Stornobedingungen, Rechnungen und Meldepflichten verantwortlich. Online-Zahlungen deiner Gäste laufen über dein eigenes Stripe-Konto.', termine: 'Der Terminplaner ist nicht für den Gesundheitsbereich gedacht. Das fragen wir im Fragebogen ab.', }) }) test('alle Wortlaute: du-Form, kein Preis, nur {fassung} als Platzhalter, tief eingefroren', () => { const alle = JSON.stringify(WORTLAUT_V6) assert.doesNotMatch(alle, /€|\bSie\b|\bIhr(e[nmrs]?)?\b/) assert.deepEqual([...alle.matchAll(/\{[a-z]+\}/g)].map((m) => m[0]).filter((x) => x !== '{fassung}'), []) for (const t of Object.values(WORTLAUT_V6.linkzeile)) assert.equal((t.match(/\{fassung\}/g) ?? []).length, 1) for (const o of [WORTLAUT_V6, WORTLAUT_V6.linkzeile, WORTLAUT_V6.beginn, WORTLAUT_V6.hinweis]) assert.ok(Object.isFrozen(o)) }) test('Funktionsunterlagen Fassung 6: Reihenfolge, Vorschaupfad, AVV nur wo Daten im Auftrag verarbeitet werden', () => { assert.equal(FUNKTIONEN_FASSUNG_V6, '2026-10-16') assert.deepEqual(Object.keys(FUNKTIONEN_UNTERLAGEN_V6), ['news', 'termine', 'shop', 'unterkunft', 'zeiten', 'analyse']) assert.deepEqual(FUNKTIONEN_UNTERLAGEN_V6.termine.lb, { version: '2026-10-16', url: '/neu/rechtliches/leistungsbeschreibung-terminplaner-2026-10-16.html', pdfFile: 'neu/rechtliches/leistungsbeschreibung-terminplaner-2026-10-16.pdf', anhangName: 'Leistungsbeschreibung-Terminplaner-2026-10-16.pdf' }) const slugs = Object.values(FUNKTIONEN_UNTERLAGEN_V6).flatMap((u) => [u.lb, u.avv]).filter(Boolean).map((d) => d.url.replace(/^\/neu\/rechtliches\/|-2026-10-16\.html$/g, '')) assert.deepEqual(slugs, ['leistungsbeschreibung-news', 'leistungsbeschreibung-terminplaner', 'avv-terminplaner', 'leistungsbeschreibung-webshop', 'avv-webshop', 'leistungsbeschreibung-unterkunft', 'avv-unterkunft', 'leistungsbeschreibung-zeiten', 'leistungsbeschreibung-website-analyse', 'avv-website-analyse']) assert.deepEqual([FUNKTIONEN_UNTERLAGEN_V6.news.avv, FUNKTIONEN_UNTERLAGEN_V6.zeiten.avv], [null, null]) assert.deepEqual(Object.values(FUNKTIONEN_UNTERLAGEN_V6).flatMap((u) => [u.lb, u.avv]).filter(Boolean).map((d) => d.anhangName.replace('-2026-10-16.pdf', '')), ['Leistungsbeschreibung-News-Pinnwand', 'Leistungsbeschreibung-Terminplaner', 'AVV-Terminplaner', 'Leistungsbeschreibung-Webshop', 'AVV-Webshop', 'Leistungsbeschreibung-Buchungskalender', 'AVV-Buchungskalender', 'Leistungsbeschreibung-Oeffnungszeiten-live', 'Leistungsbeschreibung-Website-Analyse', 'AVV-Website-Analyse']) }) test('Verdrahtung mit P5 (läuft erst nach dem Merge von kn/server; rot, bis der Controller verdrahtet hat)', { skip: config.aboFunktionen === undefined && 'config.aboFunktionen fehlt: P5 noch nicht gemerged' }, async () => { const reg = await import('../server/services/featureRegistry.js') assert.equal(config.aboFunktionen.fassung, FUNKTIONEN_FASSUNG_V6) assert.equal(config.aboFunktionen.texte.beginn, WORTLAUT_V6.beginn.einrichtung) for (const key of ['termine', 'shop', 'unterkunft']) assert.equal(reg.consentAbo(key).items[0].text, mitFassung(WORTLAUT_V6.linkzeile.einschaltenMitAvv, FUNKTIONEN_FASSUNG_V6), key) for (const key of ['news', 'zeiten']) assert.equal(reg.consentAbo(key).items[0].text, mitFassung(WORTLAUT_V6.linkzeile.einschaltenOhneAvv, FUNKTIONEN_FASSUNG_V6), key) })