Widerrufsbelehrung nach Anlage 1 (Stand 2026, mit Hinweis auf die Widerrufsfunktion), Formular nach Anlage 2, Muster-AGB ohne OS-Plattform, erzeugter Versand-/Zahlungstext, Gewaehrleistungshinweis (Wortlaut zu pruefen), Muster-Markdown fuer die Kanzlei und Tests inkl. Abgleich Markdown/Code. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
312 lines
18 KiB
JavaScript
312 lines
18 KiB
JavaScript
import { test } from 'node:test'
|
||
import assert from 'node:assert/strict'
|
||
import { readFileSync } from 'node:fs'
|
||
import {
|
||
musterWiderrufsbelehrung,
|
||
musterWiderrufsformular,
|
||
musterAgb,
|
||
versandUndZahlung,
|
||
gewaehrleistungsHinweis,
|
||
zahlungsartenText,
|
||
normalisiereRechtstexte,
|
||
vollstaendig,
|
||
rechtstexteHash,
|
||
BESTAETIGUNG_TEXT,
|
||
} from '../server/services/shop/rechtstexte.js'
|
||
import { STANDARD_EINSTELLUNGEN } from '../server/services/shop/einstellungen.js'
|
||
|
||
const NB = '\u00a0'
|
||
const basis = () => {
|
||
const e = JSON.parse(JSON.stringify(STANDARD_EINSTELLUNGEN))
|
||
e.anbieter = { name: 'Brot & Mehr GmbH', strasse: 'Hauptstraße 5', plz: '67655', ort: 'Kaiserslautern', land: 'DE', email: 'shop@brot.example', telefon: '0631 123456', ustId: 'DE123456789' }
|
||
return e
|
||
}
|
||
const WIDERRUF_URL = 'https://brot.example/shop#widerruf'
|
||
|
||
test('Widerrufsbelehrung: gesetzliche Kernsaetze und eingesetzte Anbieterdaten', () => {
|
||
const t = musterWiderrufsbelehrung(basis(), { widerrufUrl: WIDERRUF_URL })
|
||
for (const s of [
|
||
'Sie haben das Recht, binnen vierzehn Tagen ohne Angabe von Gründen diesen Vertrag zu widerrufen.',
|
||
'Die Widerrufsfrist beträgt vierzehn Tage ab dem Tag, an dem Sie oder ein von Ihnen benannter Dritter, der nicht der Beförderer ist, die Waren in Besitz genommen haben bzw. hat.',
|
||
'die letzte Ware in Besitz genommen haben bzw. hat.',
|
||
'mittels einer eindeutigen Erklärung (z. B. ein mit der Post versandter Brief oder eine E-Mail)',
|
||
'Sie können dafür das beigefügte Muster-Widerrufsformular verwenden, das jedoch nicht vorgeschrieben ist.',
|
||
'Zur Wahrung der Widerrufsfrist reicht es aus, dass Sie die Mitteilung über die Ausübung des Widerrufsrechts vor Ablauf der Widerrufsfrist absenden.',
|
||
'unverzüglich und spätestens binnen vierzehn Tagen ab dem Tag zurückzuzahlen, an dem die Mitteilung über Ihren Widerruf dieses Vertrags bei uns eingegangen ist.',
|
||
'in keinem Fall werden Ihnen wegen dieser Rückzahlung Entgelte berechnet.',
|
||
'Wir können die Rückzahlung verweigern, bis wir die Waren wieder zurückerhalten haben oder bis Sie den Nachweis erbracht haben, dass Sie die Waren zurückgesandt haben, je nachdem, welches der frühere Zeitpunkt ist.',
|
||
'Sie müssen für einen etwaigen Wertverlust der Waren nur aufkommen, wenn dieser Wertverlust auf einen zur Prüfung der Beschaffenheit, Eigenschaften und Funktionsweise der Waren nicht notwendigen Umgang mit ihnen zurückzuführen ist.',
|
||
]) {
|
||
assert.ok(t.includes(s), `fehlt: ${s}`)
|
||
}
|
||
assert.ok(t.includes('(Brot & Mehr GmbH, Hauptstraße 5, 67655 Kaiserslautern, Telefon: 0631 123456, E-Mail: shop@brot.example)'))
|
||
assert.ok(t.includes('an uns (Brot & Mehr GmbH, Hauptstraße 5, 67655 Kaiserslautern) zurückzusenden oder zu übergeben'))
|
||
assert.ok(!t.includes('['), 'keine offenen Platzhalter bei vollen Angaben')
|
||
assert.ok(t.split('\n\n').length > 10)
|
||
})
|
||
|
||
test('Widerrufsbelehrung: Hinweis auf die Widerrufsfunktion mit Adresse', () => {
|
||
const t = musterWiderrufsbelehrung(basis(), { widerrufUrl: WIDERRUF_URL })
|
||
assert.ok(t.includes(`Sie können Ihr Widerrufsrecht auch online unter ${WIDERRUF_URL} ausüben.`))
|
||
assert.ok(
|
||
t.includes(
|
||
'Wenn Sie diese Online-Funktion nutzen, übermitteln wir Ihnen auf einem dauerhaften Datenträger (z. B. durch eine E-Mail) unverzüglich eine Eingangsbestätigung mit Informationen zum Inhalt der Widerrufserklärung sowie dem Datum und der Uhrzeit ihres Eingangs.'
|
||
)
|
||
)
|
||
// ohne Adresse: sichtbarer Platzhalter statt leerer Stelle
|
||
assert.ok(musterWiderrufsbelehrung(basis()).includes('[Internetadresse der Widerrufsfunktion]'))
|
||
})
|
||
|
||
test('Widerrufsbelehrung: Variante Ruecksendekosten', () => {
|
||
const e = basis()
|
||
assert.ok(musterWiderrufsbelehrung(e, { widerrufUrl: WIDERRUF_URL }).includes('Sie tragen die unmittelbaren Kosten der Rücksendung der Waren.'))
|
||
e.ruecksendekosten = 'haendler'
|
||
const t = musterWiderrufsbelehrung(e, { widerrufUrl: WIDERRUF_URL })
|
||
assert.ok(t.includes('Wir tragen die Kosten der Rücksendung der Waren.'))
|
||
assert.ok(!t.includes('Sie tragen die unmittelbaren Kosten'))
|
||
})
|
||
|
||
test('Widerrufsbelehrung: Abholung nur wenn angeboten', () => {
|
||
const e = basis()
|
||
assert.ok(!musterWiderrufsbelehrung(e, { widerrufUrl: WIDERRUF_URL }).includes('abgeholt'))
|
||
e.abholung = { aktiv: true, adresse: 'Lager, Bahnhofstraße 1, 67655 Kaiserslautern', hinweis: '' }
|
||
assert.ok(musterWiderrufsbelehrung(e, { widerrufUrl: WIDERRUF_URL }).includes('Haben Sie die Waren bei uns abgeholt, übergeben Sie diese zur Rückgabe an unserer Anschrift: Lager, Bahnhofstraße 1, 67655 Kaiserslautern.'))
|
||
})
|
||
|
||
test('Widerrufsbelehrung: Ausschluss und vorzeitiges Erlöschen nach § 312g Abs. 2 Nr. 1, 2, 3', () => {
|
||
const t = musterWiderrufsbelehrung(basis(), { widerrufUrl: WIDERRUF_URL })
|
||
assert.ok(t.includes('Ausschluss bzw. vorzeitiges Erlöschen des Widerrufsrechts'))
|
||
assert.ok(t.includes('die nicht vorgefertigt sind und für deren Herstellung eine individuelle Auswahl oder Bestimmung durch den Verbraucher maßgeblich ist oder die eindeutig auf die persönlichen Bedürfnisse des Verbrauchers zugeschnitten sind (§ 312g Abs. 2 Nr. 1 BGB)'))
|
||
assert.ok(t.includes('Waren, die schnell verderben können oder deren Verfallsdatum schnell überschritten würde (§ 312g Abs. 2 Nr. 2 BGB)'))
|
||
assert.ok(t.includes('Das Widerrufsrecht erlischt vorzeitig bei Verträgen zur Lieferung versiegelter Waren, die aus Gründen des Gesundheitsschutzes oder der Hygiene nicht zur Rückgabe geeignet sind, wenn ihre Versiegelung nach der Lieferung entfernt wurde (§ 312g Abs. 2 Nr. 3 BGB)'))
|
||
})
|
||
|
||
test('Widerrufsbelehrung: leere Anbieterdaten ergeben Platzhalter, kein Absturz', () => {
|
||
const t = musterWiderrufsbelehrung(STANDARD_EINSTELLUNGEN, { widerrufUrl: WIDERRUF_URL })
|
||
assert.ok(t.includes('[Name]'))
|
||
assert.ok(t.includes('[Anschrift]'))
|
||
assert.ok(t.includes('[E-Mail-Adresse]'))
|
||
assert.doesNotThrow(() => musterWiderrufsbelehrung(undefined))
|
||
assert.doesNotThrow(() => musterAgb({}))
|
||
assert.doesNotThrow(() => versandUndZahlung(null))
|
||
})
|
||
|
||
test('Widerrufsformular nach Anlage 2 mit Anschrift', () => {
|
||
const t = musterWiderrufsformular(basis())
|
||
assert.ok(t.includes('An Brot & Mehr GmbH, Hauptstraße 5, 67655 Kaiserslautern, E-Mail: shop@brot.example:'))
|
||
assert.ok(t.includes('Hiermit widerrufe(n) ich/wir (*) den von mir/uns (*) abgeschlossenen Vertrag über den Kauf der folgenden Waren (*)/die Erbringung der folgenden Dienstleistung (*)'))
|
||
assert.ok(t.includes('– Bestellt am (*)/erhalten am (*)'))
|
||
assert.ok(t.includes('– Name des/der Verbraucher(s)'))
|
||
assert.ok(t.includes('– Unterschrift des/der Verbraucher(s) (nur bei Mitteilung auf Papier)'))
|
||
assert.ok(t.includes('(*) Unzutreffendes streichen.'))
|
||
assert.ok(t.startsWith('Muster-Widerrufsformular'))
|
||
})
|
||
|
||
test('AGB: Kopf, Paragraphen, Vertragsschluss, Zahlung, Streitbeilegung ohne OS-Plattform', () => {
|
||
const e = basis()
|
||
e.zahlungsarten = ['card', 'klarna', 'sepa_debit']
|
||
e.versand.laender = ['DE', 'AT']
|
||
e.kleinunternehmer = false
|
||
const t = musterAgb(e)
|
||
assert.ok(t.startsWith('Muster – bitte prüfen und anpassen'))
|
||
for (let i = 1; i <= 10; i += 1) assert.ok(new RegExp(`^§ ${i} `, 'm').test(t), `§ ${i} fehlt`)
|
||
assert.ok(t.includes('Mit dem Klick auf die Schaltfläche „Zahlungspflichtig bestellen“ geben Sie eine verbindliche Bestellung ab.'))
|
||
assert.ok(t.includes('Der Vertrag kommt zustande, sobald wir Ihnen nach erfolgreicher Zahlung die Bestellbestätigung per E-Mail senden.'))
|
||
assert.ok(t.includes('Die Zahlung erfolgt über den Zahlungsdienstleister Stripe.'))
|
||
assert.ok(t.includes('Kreditkarte, Apple Pay, Google Pay, Klarna, SEPA-Lastschrift'))
|
||
assert.ok(t.includes('Bei SEPA-Lastschrift versenden wir die Ware erst nach Eingang der Zahlung.'))
|
||
assert.ok(t.includes('Wir liefern in folgende Länder: Deutschland, Österreich.'))
|
||
assert.ok(t.includes('Die Lieferzeit beträgt 2–4 Werktage'))
|
||
assert.ok(t.includes('Die Waren bleiben bis zur vollständigen Bezahlung unser Eigentum.'))
|
||
assert.ok(t.includes('Es gelten die gesetzlichen Mängelhaftungsrechte.'))
|
||
assert.ok(t.includes('Wir speichern den Vertragstext nach Vertragsschluss nicht für Sie abrufbar.'))
|
||
assert.ok(t.includes('Die Vertragssprache ist Deutsch.'))
|
||
assert.ok(t.includes('ist nicht bereit und nicht verpflichtet, an einem Streitbeilegungsverfahren vor einer Verbraucherschlichtungsstelle teilzunehmen (§ 36 VSBG)'))
|
||
assert.ok(t.includes('Alle Preise enthalten die gesetzliche Umsatzsteuer.'))
|
||
assert.ok(t.includes('USt-IdNr.: DE123456789'))
|
||
assert.doesNotMatch(t, /ec\.europa\.eu|OS-Plattform|ODR/i)
|
||
})
|
||
|
||
test('AGB: Varianten Kleinunternehmer, nur Karte, Abholung, kein Versand', () => {
|
||
const e = basis()
|
||
e.kleinunternehmer = true
|
||
e.abholung = { aktiv: true, adresse: 'Laden, Hauptstraße 5', hinweis: 'Di–Fr 9–17 Uhr' }
|
||
e.versand.aktiv = false
|
||
const t = musterAgb(e)
|
||
assert.ok(t.includes('Gemäß § 19 UStG wird keine Umsatzsteuer berechnet und ausgewiesen.'))
|
||
assert.ok(!t.includes('SEPA'), 'SEPA-Satz nur bei SEPA')
|
||
assert.ok(!t.includes('Wir liefern in folgende Länder'))
|
||
assert.ok(t.includes('Sie können die Waren auch bei uns abholen: Laden, Hauptstraße 5. Di–Fr 9–17 Uhr'))
|
||
})
|
||
|
||
test('versandUndZahlung: Liefergebiet, Kosten je Land, frei ab, Abholung, Zahlungsarten, Mindestbestellwert', () => {
|
||
const e = basis()
|
||
e.versand = { aktiv: true, laender: ['DE', 'AT'], kostenCent: { DE: 490, AT: 990 }, freiAbCent: 5000 }
|
||
e.abholung = { aktiv: true, adresse: 'Laden, Hauptstraße 5', hinweis: 'Di–Fr 9–17 Uhr' }
|
||
e.zahlungsarten = ['card', 'klarna']
|
||
e.mindestbestellCent = 1000
|
||
e.kleinunternehmer = false
|
||
const t = versandUndZahlung(e)
|
||
assert.ok(t.includes('Liefergebiet: Deutschland, Österreich'))
|
||
assert.ok(t.includes(`Deutschland: 4,90${NB}€`))
|
||
assert.ok(t.includes(`Österreich: 9,90${NB}€`))
|
||
assert.ok(t.includes(`Versandkostenfrei ab einem Bestellwert von 50,00${NB}€.`))
|
||
assert.ok(t.includes('Abholung: Laden, Hauptstraße 5\nDi–Fr 9–17 Uhr'))
|
||
assert.ok(t.includes('Lieferzeit: 2–4 Werktage'))
|
||
assert.ok(t.includes('Zahlungsarten: Kreditkarte, Apple Pay, Google Pay, Klarna'))
|
||
assert.ok(t.includes(`Mindestbestellwert: 10,00${NB}€`))
|
||
assert.ok(t.includes('Alle Preise inkl. gesetzlicher USt.'))
|
||
e.kleinunternehmer = true
|
||
e.mindestbestellCent = null
|
||
e.versand.freiAbCent = null
|
||
e.abholung.aktiv = false
|
||
const k = versandUndZahlung(e)
|
||
assert.ok(k.includes('§ 19 UStG'))
|
||
assert.ok(!k.includes('Mindestbestellwert'))
|
||
assert.ok(!k.includes('Versandkostenfrei'))
|
||
assert.ok(!k.includes('Abholung'))
|
||
e.versand.aktiv = false
|
||
assert.ok(versandUndZahlung(e).includes('Wir versenden derzeit nicht.'))
|
||
})
|
||
|
||
test('zahlungsartenText: feste Reihenfolge, nur aktive Arten', () => {
|
||
assert.equal(zahlungsartenText({ zahlungsarten: ['card'] }), 'Kreditkarte, Apple Pay, Google Pay')
|
||
assert.equal(zahlungsartenText({ zahlungsarten: ['klarna', 'card'] }), 'Kreditkarte, Apple Pay, Google Pay, Klarna')
|
||
assert.equal(zahlungsartenText({ zahlungsarten: ['sepa_debit', 'klarna'] }), 'Klarna, SEPA-Lastschrift')
|
||
assert.equal(zahlungsartenText({ zahlungsarten: ['paypal', 'card'] }), 'Kreditkarte, Apple Pay, Google Pay')
|
||
assert.equal(zahlungsartenText({}), '')
|
||
assert.equal(zahlungsartenText(undefined), '')
|
||
})
|
||
|
||
test('Gewaehrleistungshinweis: zwei Jahre, stabil, ohne Platzhalter', () => {
|
||
const t = gewaehrleistungsHinweis()
|
||
assert.ok(t.startsWith('Gesetzliches Gewährleistungsrecht'))
|
||
assert.ok(t.includes('mindestens zwei Jahren'))
|
||
assert.equal(gewaehrleistungsHinweis(), t)
|
||
})
|
||
|
||
test('BESTAETIGUNG_TEXT genau nach Spec 4.6', () => {
|
||
assert.equal(BESTAETIGUNG_TEXT, 'Ich habe die Texte geprüft. Ich bin als Verkäufer für Rechtstexte, Produktangaben und Preise verantwortlich. WEBklar stellt Muster bereit und berät nicht rechtlich.')
|
||
})
|
||
|
||
test('normalisiereRechtstexte: gueltig, Entwurf mit leeren Texten, Bereinigung', () => {
|
||
const r = normalisiereRechtstexte({
|
||
agb: ' Zeile 1\r\nZeile 2 \n\n\n\nZeile 3 ',
|
||
widerrufsbelehrung: 'B',
|
||
widerrufsformular: 'F',
|
||
impressumUrl: ' https://brot.example/impressum ',
|
||
datenschutzUrl: 'https://brot.example/datenschutz?x=1#a',
|
||
unbekannt: 'wird ignoriert',
|
||
})
|
||
assert.deepEqual(r, {
|
||
rechtstexte: {
|
||
agb: 'Zeile 1\nZeile 2\n\nZeile 3',
|
||
widerrufsbelehrung: 'B',
|
||
widerrufsformular: 'F',
|
||
impressumUrl: 'https://brot.example/impressum',
|
||
datenschutzUrl: 'https://brot.example/datenschutz?x=1#a',
|
||
},
|
||
})
|
||
const leer = normalisiereRechtstexte({})
|
||
assert.deepEqual(leer, { rechtstexte: { agb: '', widerrufsbelehrung: '', widerrufsformular: '', impressumUrl: '', datenschutzUrl: '' } })
|
||
assert.equal(vollstaendig(leer.rechtstexte), false)
|
||
})
|
||
|
||
test('normalisiereRechtstexte: Laengen', () => {
|
||
assert.ok(normalisiereRechtstexte({ agb: 'a'.repeat(30000) }).rechtstexte)
|
||
assert.ok(normalisiereRechtstexte({ agb: 'a'.repeat(30001) }).fehler.agb)
|
||
assert.ok(normalisiereRechtstexte({ widerrufsbelehrung: 'a'.repeat(20000) }).rechtstexte)
|
||
assert.ok(normalisiereRechtstexte({ widerrufsbelehrung: 'a'.repeat(20001) }).fehler.widerrufsbelehrung)
|
||
assert.ok(normalisiereRechtstexte({ widerrufsformular: 'a'.repeat(5000) }).rechtstexte)
|
||
assert.ok(normalisiereRechtstexte({ widerrufsformular: 'a'.repeat(5001) }).fehler.widerrufsformular)
|
||
})
|
||
|
||
test('normalisiereRechtstexte: URLs nur https ohne Zugangsdaten und Leerraum', () => {
|
||
for (const u of ['http://x.example/a', 'javascript:alert(1)', 'ftp://x.example', '//x.example/a', 'x.example/impressum', 'https://user:pw@x.example/a', 'https://user@x.example/a', 'https://x.example/a b', 'https://', 'data:text/html,hi']) {
|
||
const r = normalisiereRechtstexte({ impressumUrl: u })
|
||
assert.ok(r.fehler?.impressumUrl, `muss abgelehnt werden: ${u}`)
|
||
}
|
||
assert.ok(normalisiereRechtstexte({ datenschutzUrl: 'https://' + 'a'.repeat(500) + '.example' }).fehler.datenschutzUrl)
|
||
assert.ok(normalisiereRechtstexte({ datenschutzUrl: 'https://x.example/datenschutz' }).rechtstexte)
|
||
assert.equal(normalisiereRechtstexte({ impressumUrl: '' }).rechtstexte.impressumUrl, '')
|
||
})
|
||
|
||
test('normalisiereRechtstexte: falsche Typen und Nicht-Objekte', () => {
|
||
for (const v of [null, undefined, 'x', 5, [], true]) assert.ok(normalisiereRechtstexte(v).fehler.rechtstexte)
|
||
const r = normalisiereRechtstexte({ agb: 5, widerrufsbelehrung: {}, impressumUrl: 7 })
|
||
assert.ok(r.fehler.agb && r.fehler.widerrufsbelehrung && r.fehler.impressumUrl)
|
||
assert.ok(!('rechtstexte' in r))
|
||
// Prototyp-Schluessel werden nie gelesen
|
||
const p = normalisiereRechtstexte(JSON.parse('{"__proto__":{"agb":"x"}}'))
|
||
assert.equal(p.rechtstexte.agb, '')
|
||
})
|
||
|
||
test('vollstaendig: alle drei Texte und beide URLs', () => {
|
||
const voll = { agb: 'a', widerrufsbelehrung: 'b', widerrufsformular: 'c', impressumUrl: 'https://x.example/i', datenschutzUrl: 'https://x.example/d' }
|
||
assert.equal(vollstaendig(voll), true)
|
||
for (const k of Object.keys(voll)) {
|
||
assert.equal(vollstaendig({ ...voll, [k]: '' }), false, k)
|
||
assert.equal(vollstaendig({ ...voll, [k]: ' ' }), false, `${k} nur Leerraum`)
|
||
}
|
||
assert.equal(vollstaendig(null), false)
|
||
assert.equal(vollstaendig(undefined), false)
|
||
})
|
||
|
||
test('rechtstexteHash: stabil, sha256 hex, reagiert auf jedes Feld und die Einstellungen', () => {
|
||
const e = basis()
|
||
const r = { agb: 'a', widerrufsbelehrung: 'b', widerrufsformular: 'c', impressumUrl: 'https://x.example/i', datenschutzUrl: 'https://x.example/d' }
|
||
const h = rechtstexteHash(r, e)
|
||
assert.match(h, /^[0-9a-f]{64}$/)
|
||
assert.equal(rechtstexteHash({ ...r }, JSON.parse(JSON.stringify(e))), h)
|
||
// Reihenfolge der Schluessel spielt keine Rolle
|
||
assert.equal(rechtstexteHash({ datenschutzUrl: r.datenschutzUrl, impressumUrl: r.impressumUrl, widerrufsformular: 'c', widerrufsbelehrung: 'b', agb: 'a' }, e), h)
|
||
// zusaetzliche Felder zaehlen nicht
|
||
assert.equal(rechtstexteHash({ ...r, extra: 'x' }, e), h)
|
||
for (const k of Object.keys(r)) assert.notEqual(rechtstexteHash({ ...r, [k]: `${r[k]}x` }, e), h, k)
|
||
// Versand-/Zahlungstext fliesst ein
|
||
const e2 = JSON.parse(JSON.stringify(e))
|
||
e2.versand.kostenCent.DE = 590
|
||
assert.notEqual(rechtstexteHash(r, e2), h)
|
||
const e3 = JSON.parse(JSON.stringify(e))
|
||
e3.zahlungsarten = ['card', 'klarna']
|
||
assert.notEqual(rechtstexteHash(r, e3), h)
|
||
// Felder ohne Einfluss auf den erzeugten Text aendern den Hash nicht
|
||
const e4 = JSON.parse(JSON.stringify(e))
|
||
e4.akzent = '#ff0000'
|
||
assert.equal(rechtstexteHash(r, e4), h)
|
||
// fehlende Felder wie leere Texte
|
||
assert.equal(rechtstexteHash({}, e), rechtstexteHash({ agb: '', widerrufsbelehrung: '', widerrufsformular: '', impressumUrl: '', datenschutzUrl: '' }, e))
|
||
})
|
||
|
||
test('Markdown-Muster und Code teilen die Kernsaetze', () => {
|
||
const md = readFileSync(new URL('../docs/funktionen/shop-muster-rechtstexte.md', import.meta.url), 'utf8')
|
||
assert.ok(md.includes('Muster – keine Rechtsberatung'))
|
||
const e = basis()
|
||
e.zahlungsarten = ['card', 'klarna', 'sepa_debit']
|
||
e.kleinunternehmer = false
|
||
// Absaetze ohne Haendlerdaten muessen wortgleich im Markdown stehen
|
||
const absaetze = [
|
||
...musterWiderrufsbelehrung(e, { widerrufUrl: WIDERRUF_URL }).split('\n\n'),
|
||
...musterAgb(e).split('\n\n'),
|
||
...musterWiderrufsformular(e).split('\n\n'),
|
||
...gewaehrleistungsHinweis().split('\n\n'),
|
||
]
|
||
const ohneDaten = absaetze.filter((a) => !/Brot & Mehr|brot\.example|Hauptstra|Kaiserslautern|2–4 Werktage|0631|DE123456789/.test(a))
|
||
assert.ok(ohneDaten.length >= 25, `zu wenige vergleichbare Absaetze: ${ohneDaten.length}`)
|
||
const mdFlach = md.replace(/ {2}\n/g, '\n')
|
||
for (const a of ohneDaten) assert.ok(mdFlach.includes(a), `im Markdown fehlt: ${a.slice(0, 80)}`)
|
||
// Absaetze mit Haendlerdaten: Kernsaetze davon
|
||
for (const s of [
|
||
'Mit dem Klick auf die Schaltfläche „Zahlungspflichtig bestellen“ geben Sie eine verbindliche Bestellung ab.',
|
||
'Der Vertrag kommt zustande, sobald wir Ihnen nach erfolgreicher Zahlung die Bestellbestätigung per E-Mail senden.',
|
||
'Sie können dafür das beigefügte Muster-Widerrufsformular verwenden, das jedoch nicht vorgeschrieben ist.',
|
||
'Wenn Sie diese Online-Funktion nutzen, übermitteln wir Ihnen auf einem dauerhaften Datenträger (z. B. durch eine E-Mail) unverzüglich eine Eingangsbestätigung',
|
||
'ist nicht bereit und nicht verpflichtet, an einem Streitbeilegungsverfahren vor einer Verbraucherschlichtungsstelle teilzunehmen (§ 36 VSBG)',
|
||
'Hiermit widerrufe(n) ich/wir (*) den von mir/uns (*) abgeschlossenen Vertrag',
|
||
]) {
|
||
assert.ok(md.includes(s), `Markdown: ${s}`)
|
||
}
|
||
assert.ok(md.includes('Wir tragen die Kosten der Rücksendung der Waren.'))
|
||
assert.doesNotMatch(md, /ec\.europa\.eu\/consumers\/odr/)
|
||
})
|