Terminplaner: Mailvorlagen G01–G08, K20, K21
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
171b5086b1
commit
274192e88e
11 files changed
+868
-21
No files matched your search
+252
-21
@@ -5,27 +5,11 @@ import { escapeHtml, htmlToText, loadTemplate, renderMail, templateIds } from '.
|
||||
import { contractAttachmentFor, termsDocFor } from '../server/services/products.js'
|
||||
|
||||
const DIR = new URL('../server/mail-templates/', import.meta.url)
|
||||
// K12, K14 und T12 (Wechsel ins Wartungs-Abo) aus Task 9, K13 und T13 (Zusatzspeicher) aus Task 8 (Fix 1);
|
||||
// Endfassung der Texte in Task 12; T14 „Löschfristen“ aus Task 21 (F39); T15 Push-Zeitmail; K15, K16, T16 Funktionen (News-Pinnwand); T17 Repo zuordnen; K17 Chat-Hinweis an Kunden; K18, K19 Website-Analyse; T18 Bankzugang erneuern (Finanzen)
|
||||
const EXPECTED = [
|
||||
...Array.from({ length: 11 }, (_, i) => `K${String(i + 1).padStart(2, '0')}`),
|
||||
'K12',
|
||||
'K13',
|
||||
'K14',
|
||||
'K15',
|
||||
'K16',
|
||||
'K17',
|
||||
'K18',
|
||||
'K19',
|
||||
...Array.from({ length: 11 }, (_, i) => `T${String(i + 1).padStart(2, '0')}`),
|
||||
'T12',
|
||||
'T13',
|
||||
'T14',
|
||||
'T15',
|
||||
'T16',
|
||||
'T17',
|
||||
'T18',
|
||||
]
|
||||
// G01–G08 Gästemails des Terminplaners (Task 9, neutrales Layout im Auftrag eines Betriebs), K20 und K21 Hinweise an den Betrieb;
|
||||
// K12, K14 und T12 (Wechsel ins Wartungs-Abo) aus Task 9, K13 und T13 (Zusatzspeicher) aus Task 8 (Fix 1); Endfassung der Texte in Task 12; T14 „Löschfristen“ aus Task 21 (F39); T15 Push-Zeitmail; K15, K16, T16 Funktionen (News-Pinnwand); T17 Repo zuordnen; K17 Chat-Hinweis an Kunden; K18, K19 Website-Analyse; T18 Bankzugang erneuern (Finanzen)
|
||||
const ids = (prefix, count) => Array.from({ length: count }, (_, i) => `${prefix}${String(i + 1).padStart(2, '0')}`)
|
||||
const EXPECTED = [...ids('G', 8), ...ids('K', 21), ...ids('T', 18)]
|
||||
const GUEST = ids('G', 8)
|
||||
|
||||
const sampleValues = (tpl) => Object.fromEntries(tpl.placeholders.map((p) => [p, `Wert-${p}`]))
|
||||
const allBlocks = (tpl, on) => Object.fromEntries(tpl.blocks.map((b) => [b, on]))
|
||||
@@ -525,3 +509,250 @@ test('T01: Knopf antwortet im Ticketsystem beim Kunden (team_link)', () => {
|
||||
assert.deepEqual(mail.problems, [])
|
||||
assert.match(mail.html, /<a href="https:\/\/ticket\.webklar\.com\/customers\/chat\?kunde=c1"[^>]*>Im Ticketsystem antworten →<\/a>/)
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Terminplaner (Task 9): G01–G08 an Gäste, K20 und K21 an den Betrieb
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const sourceOf = (id) => readFileSync(new URL(loadTemplate(id).file, DIR), 'utf8')
|
||||
const FOOTER_SENTENCE = 'Diese E-Mail wurde im Auftrag von Wert-betrieb_name über den Terminplaner von WEBklar versendet.'
|
||||
// Sie-Formen und Du-Formen (der Rechtstext der Widerrufsbelehrung ist ein Platzhalterwert und kommt hier nicht vor)
|
||||
const SIE_FORM = /(^|[^\p{L}])(Sie|Ihr\p{L}*|Ihnen)(?![\p{L}-])/u
|
||||
const DU_FORM = /(^|[^\p{L}])(du|dein\p{L}*|dir|dich)(?![\p{L}-])/iu
|
||||
const anrede = (tpl, sie, extra = {}) => ({ ...allBlocks(tpl, true), ...extra, sie, du: !sie })
|
||||
|
||||
test('G-Vorlagen: Betreff ist {{betreff}}, Blöcke sie und du, Platzhalter für Farbe und Betriebsfuß', () => {
|
||||
for (const id of GUEST) {
|
||||
const tpl = loadTemplate(id)
|
||||
assert.equal(tpl.subject, '{{betreff}}', id)
|
||||
for (const block of ['sie', 'du']) assert.ok(tpl.blocks.includes(block), `${id}: Block ${block}`)
|
||||
for (const p of ['betreff', 'farbe', 'betrieb_name', 'betrieb_adresse', 'betrieb_telefon', 'betrieb_email', 'impressum_url', 'datenschutz_url']) {
|
||||
assert.ok(tpl.placeholders.includes(p), `${id}: ${p}`)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test('G-Vorlagen: neutrales Layout, Kopf in der Betriebsfarbe, Fuß mit Betrieb, Links und Satz über den Terminplaner', () => {
|
||||
for (const id of GUEST) {
|
||||
const tpl = loadTemplate(id)
|
||||
const source = sourceOf(id)
|
||||
assert.match(source, /<td[^>]*style="[^"]*background:\{\{farbe\}\}/, `${id}: Kopfbalken in {{farbe}}`)
|
||||
assert.doesNotMatch(source, /<img|webklar-logo|project\.webklar\.com/i, `${id}: kein Bild, kein WEBklar-Logo, keine Portal-Adresse`)
|
||||
assert.doesNotMatch(source, /https?:\/\/(?!www\.w3\.org)|google|tracking|pixel/i, `${id}: keine festen Adressen, keine Werbung, kein Tracking`)
|
||||
for (const on of [true, false]) {
|
||||
const mail = renderMail(id, sampleValues(tpl), { ...allBlocks(tpl, on), sie: true, du: false })
|
||||
assert.deepEqual(mail.problems, [], id)
|
||||
assert.ok(mail.text.includes(FOOTER_SENTENCE), `${id}: Fußsatz\n${mail.text}`)
|
||||
for (const wert of ['Wert-betrieb_adresse', 'Wert-betrieb_telefon', 'Wert-betrieb_email']) assert.ok(mail.text.includes(wert), `${id}: ${wert}`)
|
||||
assert.match(mail.html, /href="Wert-impressum_url"[^>]*>Impressum</, id)
|
||||
assert.match(mail.html, /href="Wert-datenschutz_url"[^>]*>Datenschutz</, id)
|
||||
assert.match(mail.html, /background:Wert-farbe/, id)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test('G-Vorlagen: jeder Anredetext steht in sie und du, Du-Mail ohne Sie-Formen und Sie-Mail ohne Du-Formen', () => {
|
||||
for (const id of GUEST) {
|
||||
const tpl = loadTemplate(id)
|
||||
const du = renderMail(id, sampleValues(tpl), anrede(tpl, false))
|
||||
const sie = renderMail(id, sampleValues(tpl), anrede(tpl, true))
|
||||
assert.deepEqual([du.problems, sie.problems], [[], []], id)
|
||||
assert.doesNotMatch(du.text, SIE_FORM, `${id}: Du-Fassung enthält Sie-Form\n${du.text}`)
|
||||
assert.doesNotMatch(du.text, / Sie | Ihr /, id)
|
||||
assert.doesNotMatch(sie.text, DU_FORM, `${id}: Sie-Fassung enthält Du-Form\n${sie.text}`)
|
||||
assert.match(sie.text, SIE_FORM, `${id}: Sie-Fassung spricht den Gast an`)
|
||||
assert.match(du.text, DU_FORM, `${id}: Du-Fassung spricht den Gast an`)
|
||||
assert.notEqual(du.text, sie.text, id)
|
||||
// ohne gesetzte Anrede erscheint kein Anredetext (der Server setzt genau einen der beiden Blöcke)
|
||||
const neither = renderMail(id, sampleValues(tpl), { ...allBlocks(tpl, true), sie: false, du: false })
|
||||
assert.doesNotMatch(neither.text, SIE_FORM, id)
|
||||
assert.doesNotMatch(neither.text, DU_FORM, id)
|
||||
}
|
||||
})
|
||||
|
||||
test('G02: Du-Mail enthält im Text kein „ Sie “ und kein „Ihr “', () => {
|
||||
const tpl = loadTemplate('G02')
|
||||
const mail = renderMail('G02', sampleValues(tpl), { ...allBlocks(tpl, true), sie: false, du: true })
|
||||
assert.deepEqual(mail.problems, [])
|
||||
assert.doesNotMatch(mail.text, / Sie |Ihr /)
|
||||
assert.doesNotMatch(mail.html, / Sie | Ihr /)
|
||||
})
|
||||
|
||||
test('G01 und G08 enthalten keinen vom Gast eingegebenen Text (kein Platzhalter gast_name)', () => {
|
||||
for (const id of ['G01', 'G08']) {
|
||||
assert.ok(!loadTemplate(id).placeholders.includes('gast_name'), `${id}: Platzhalter`)
|
||||
assert.ok(!sourceOf(id).includes('gast_name'), `${id}: Quelltext`)
|
||||
}
|
||||
// ... die anderen Gästemails nennen den Gast beim Namen
|
||||
for (const id of ['G02', 'G03', 'G04', 'G05', 'G06', 'G07']) assert.ok(loadTemplate(id).placeholders.includes('gast_name'), id)
|
||||
})
|
||||
|
||||
test('G-Vorlagen: Platzhalter und Blöcke wie im Plan', () => {
|
||||
const common = ['betreff', 'farbe', 'betrieb_name', 'betrieb_adresse', 'betrieb_telefon', 'betrieb_email', 'impressum_url', 'datenschutz_url']
|
||||
const expected = {
|
||||
G01: { p: ['leistung', 'datum', 'zeit', 'link'], b: ['zu_viele'] },
|
||||
G02: { p: ['gast_name', 'leistung', 'person', 'datum', 'zeit', 'dauer', 'preis', 'zahlung', 'nummer', 'link', 'ort', 'storno_text', 'widerrufsbelehrung', 'widerruf_link'], b: ['preis', 'person', 'storno', 'widerruf', 'anfrage_angenommen'] },
|
||||
G03: { p: ['gast_name', 'leistung', 'datum', 'zeit', 'link'], b: [] },
|
||||
G04: { p: ['gast_name', 'leistung', 'datum', 'zeit', 'nachricht'], b: ['nachricht'] },
|
||||
G05: { p: ['gast_name', 'leistung', 'person', 'datum', 'zeit', 'link'], b: ['person'] },
|
||||
G06: { p: ['gast_name', 'leistung', 'datum', 'zeit', 'absage_von', 'grund'], b: ['nachricht'] },
|
||||
G07: { p: ['gast_name', 'leistung', 'alt_datum', 'alt_zeit', 'datum', 'zeit', 'link'], b: [] },
|
||||
G08: { p: ['eingang', 'nummer'], b: ['zugeordnet', 'nach_frist'] },
|
||||
}
|
||||
for (const [id, { p, b }] of Object.entries(expected)) {
|
||||
const tpl = loadTemplate(id)
|
||||
assert.deepEqual([...tpl.placeholders].sort(), [...common, ...p].sort(), `${id}: Platzhalter`)
|
||||
assert.deepEqual([...tpl.blocks].sort(), ['du', 'sie', ...b].sort(), `${id}: Blöcke`)
|
||||
}
|
||||
})
|
||||
|
||||
test('G01: Knopf zur Bestätigung, Hinweis für Dritte; Block zu_viele nennt Telefon und Absagen', () => {
|
||||
const tpl = loadTemplate('G01')
|
||||
const values = { ...sampleValues(tpl), betrieb_name: 'Salon Muster', betrieb_telefon: '06301 1234', leistung: 'Herrenschnitt', datum: 'Montag, 12.10.2026', zeit: '10:00', link: 'https://project.webklar.com/termin.html#v=abc' }
|
||||
const sie = renderMail('G01', values, { sie: true })
|
||||
assert.deepEqual(sie.problems, [])
|
||||
assert.match(sie.text, /Leistung: Herrenschnitt/)
|
||||
assert.match(sie.text, /Datum: Montag, 12\.10\.2026/)
|
||||
assert.match(sie.text, /Uhrzeit: 10:00 Uhr/)
|
||||
assert.match(sie.text, /Termin bestätigen: https:\/\/project\.webklar\.com\/termin\.html#v=abc/)
|
||||
assert.match(sie.text, /Das waren Sie nicht\? Dann ignorieren Sie diese E-Mail\./)
|
||||
assert.doesNotMatch(sie.text, /höchstmögliche Zahl/)
|
||||
const viele = renderMail('G01', values, { sie: true, zu_viele: true })
|
||||
assert.match(viele.text, /bereits die höchstmögliche Zahl offener Termine/)
|
||||
assert.match(viele.text, /sagen Sie einen Ihrer offenen Termine ab/)
|
||||
assert.match(viele.text, /rufen Sie uns an: 06301 1234/)
|
||||
assert.match(renderMail('G01', values, { du: true }).text, /Das warst du nicht\? Dann ignoriere diese E-Mail\./)
|
||||
})
|
||||
|
||||
test('G02: Zusammenfassung, Verwaltungslink, Preis, Person, Storno und Widerruf nur mit ihren Blöcken', () => {
|
||||
const tpl = loadTemplate('G02')
|
||||
const belehrung = 'Widerrufsbelehrung\n\nWiderrufsrecht: 14 Tage <b>ohne</b> Gründe.\nZweite Zeile & mehr'
|
||||
const values = {
|
||||
...sampleValues(tpl),
|
||||
gast_name: 'Erika Muster', leistung: 'Herrenschnitt', person: 'Anna', datum: 'Montag, 12.10.2026', zeit: '10:00', dauer: '30 Minuten',
|
||||
preis: '28,00 € inkl. USt', zahlung: 'Bezahlung vor Ort', nummer: 'AB12CD34', link: 'https://project.webklar.com/termin.html#m=tok', ort: 'Hauptstr. 1, 67722 Winnweiler',
|
||||
storno_text: 'Absage bis 24 Stunden vorher kostenlos.', widerrufsbelehrung: belehrung, widerruf_link: 'https://project.webklar.com/widerrufen.html#m=tok',
|
||||
}
|
||||
const basis = renderMail('G02', values, { sie: true })
|
||||
assert.deepEqual(basis.problems, [])
|
||||
for (const zeile of ['Guten Tag Erika Muster,', 'Leistung: Herrenschnitt', 'Datum: Montag, 12.10.2026', 'Uhrzeit: 10:00 Uhr', 'Dauer: 30 Minuten', 'Ort: Hauptstr. 1, 67722 Winnweiler', 'Buchungsnummer: AB12CD34']) {
|
||||
assert.ok(basis.text.split('\n').includes(zeile), `Zeile fehlt: ${zeile}\n${basis.text}`)
|
||||
}
|
||||
assert.match(basis.text, /Termin verwalten: https:\/\/project\.webklar\.com\/termin\.html#m=tok/)
|
||||
assert.match(basis.text, /Ihr Termin ist bestätigt/)
|
||||
assert.doesNotMatch(basis.text, /28,00|Bezahlung vor Ort|Anna|Absage bis 24 Stunden|Widerruf|angenommen/)
|
||||
|
||||
const voll = renderMail('G02', values, { sie: true, preis: true, person: true, storno: true, widerruf: true, anfrage_angenommen: true })
|
||||
assert.deepEqual(voll.problems, [])
|
||||
assert.match(voll.text, /Preis: 28,00 € inkl\. USt/)
|
||||
assert.match(voll.text, /Zahlung: Bezahlung vor Ort/)
|
||||
assert.match(voll.text, /Anna/)
|
||||
assert.match(voll.text, /Absage bis 24 Stunden vorher kostenlos\./)
|
||||
assert.match(voll.text, /Wert-betrieb_name hat Ihre Terminanfrage angenommen/)
|
||||
assert.match(voll.text, /Vertrag widerrufen: https:\/\/project\.webklar\.com\/widerrufen\.html#m=tok/)
|
||||
// Belehrung wörtlich, Zeilenumbrüche bleiben, Sonderzeichen sind maskiert
|
||||
assert.match(voll.html, /Widerrufsrecht: 14 Tage <b>ohne<\/b> Gründe\.<br>Zweite Zeile & mehr/)
|
||||
assert.ok(voll.text.includes('Widerrufsbelehrung\n\nWiderrufsrecht: 14 Tage <b>ohne</b> Gründe.\nZweite Zeile & mehr'), voll.text)
|
||||
// der Wortlaut der Belehrung steht in einem abgesetzten Kasten
|
||||
assert.match(voll.html, /class="box"[^>]*><tr><td[^>]*>Widerrufsbelehrung<br><br>Widerrufsrecht/)
|
||||
|
||||
const du = renderMail('G02', values, { du: true, anfrage_angenommen: true, widerruf: true })
|
||||
assert.match(du.text, /Dein Termin ist bestätigt/)
|
||||
assert.match(du.text, /hat deine Terminanfrage angenommen/)
|
||||
assert.doesNotMatch(du.text, SIE_FORM)
|
||||
})
|
||||
|
||||
test('G03, G04, G05, G06, G07: Inhalt je Mail', () => {
|
||||
const g03 = renderMail('G03', { ...sampleValues(loadTemplate('G03')), gast_name: 'Erika', betrieb_name: 'Salon Muster', link: 'https://x.example/m' }, { sie: true })
|
||||
assert.match(g03.text, /Salon Muster prüft sie und meldet sich bei Ihnen/)
|
||||
assert.match(g03.text, /Anfrage absagen: https:\/\/x\.example\/m/)
|
||||
|
||||
const t04 = loadTemplate('G04')
|
||||
const g04 = renderMail('G04', { ...sampleValues(t04), nachricht: 'Am Montag sind wir leider im Urlaub.' }, { sie: true })
|
||||
assert.doesNotMatch(g04.text, /Urlaub/)
|
||||
assert.match(g04.text, /leider kann Wert-betrieb_name Ihre Terminanfrage nicht annehmen/)
|
||||
assert.match(renderMail('G04', { ...sampleValues(t04), nachricht: 'Am Montag sind wir leider im Urlaub.' }, { sie: true, nachricht: true }).text, /Am Montag sind wir leider im Urlaub\./)
|
||||
|
||||
const t05 = loadTemplate('G05')
|
||||
const g05 = renderMail('G05', { ...sampleValues(t05), person: 'Anna', link: 'https://x.example/m' }, { du: true, person: true })
|
||||
assert.match(g05.text, /Anna/)
|
||||
assert.match(g05.text, /Termin verwalten: https:\/\/x\.example\/m/)
|
||||
assert.match(g05.text, /Erinnerung/)
|
||||
assert.doesNotMatch(renderMail('G05', { ...sampleValues(t05), person: 'Anna' }, { du: true }).text, /Anna/)
|
||||
|
||||
const t06 = loadTemplate('G06')
|
||||
const g06 = renderMail('G06', { ...sampleValues(t06), absage_von: 'dem Betrieb', grund: 'Krankheit im Team' }, { sie: true })
|
||||
assert.match(g06.text, /Abgesagt von: dem Betrieb/)
|
||||
assert.doesNotMatch(g06.text, /Krankheit/)
|
||||
assert.match(renderMail('G06', { ...sampleValues(t06), grund: 'Krankheit im Team' }, { sie: true, nachricht: true }).text, /Krankheit im Team/)
|
||||
|
||||
const t07 = loadTemplate('G07')
|
||||
const g07 = renderMail('G07', { ...sampleValues(t07), alt_datum: '12.10.2026', alt_zeit: '10:00', datum: '13.10.2026', zeit: '11:30' }, { du: true })
|
||||
assert.match(g07.text, /Bisher: 12\.10\.2026, 10:00 Uhr/)
|
||||
assert.match(g07.text, /Neu: 13\.10\.2026, 11:30 Uhr/)
|
||||
})
|
||||
|
||||
test('G08: Eingangsbestätigung mit Datum und Uhrzeit, Blöcke zugeordnet und nach_frist, nichts vom Gast', () => {
|
||||
const tpl = loadTemplate('G08')
|
||||
const values = { ...sampleValues(tpl), betrieb_name: 'Salon Muster', eingang: '02.10.2026, 10:07 Uhr', nummer: 'AB12CD34' }
|
||||
const ohne = renderMail('G08', values, { sie: true })
|
||||
assert.deepEqual(ohne.problems, [])
|
||||
assert.match(ohne.text, /Eingegangen am: 02\.10\.2026, 10:07 Uhr/)
|
||||
assert.match(ohne.text, /Widerruf/)
|
||||
assert.doesNotMatch(ohne.text, /AB12CD34|bereits abgelaufen/)
|
||||
const zugeordnet = renderMail('G08', values, { sie: true, zugeordnet: true })
|
||||
assert.match(zugeordnet.text, /Buchung AB12CD34/)
|
||||
assert.match(zugeordnet.text, /Der Termin ist abgesagt\./)
|
||||
assert.doesNotMatch(zugeordnet.text, /bereits abgelaufen/)
|
||||
const spaet = renderMail('G08', values, { sie: true, nach_frist: true })
|
||||
assert.match(spaet.text, /Widerrufsfrist war bei Eingang Ihrer Erklärung bereits abgelaufen/)
|
||||
assert.doesNotMatch(spaet.text, /Der Termin ist abgesagt|AB12CD34/)
|
||||
// Hinweis für Dritte: wer nichts erklärt hat, kann die Mail ignorieren
|
||||
assert.match(ohne.text, /Waren Sie das nicht, können Sie diese Nachricht ignorieren\./)
|
||||
})
|
||||
|
||||
test('K20 und K21: WEBklar-Layout in Du-Form, Gastdaten maskiert, Blöcke je Fall', () => {
|
||||
for (const id of ['K20', 'K21']) {
|
||||
const tpl = loadTemplate(id)
|
||||
assert.equal(tpl.subject, '{{betreff}}', id)
|
||||
for (const p of ['betreff', 'kunde_name', 'leistung', 'person', 'datum', 'zeit', 'gast_name', 'gast_email', 'gast_telefon', 'gast_nachricht', 'portal_link']) assert.ok(tpl.placeholders.includes(p), `${id}: ${p}`)
|
||||
assert.ok(!tpl.blocks.includes('sie') && !tpl.blocks.includes('du'), `${id}: Du-Form fest, keine Anredeblöcke`)
|
||||
const mail = renderMail(id, sampleValues(tpl), allBlocks(tpl, true))
|
||||
assert.doesNotMatch(mail.text, SIE_FORM, `${id}: Du-Form\n${mail.text}`)
|
||||
assert.match(mail.text, /Hallo Wert-kunde_name,/, id)
|
||||
assert.match(mail.html, /<a href="Wert-portal_link"/, id)
|
||||
assert.doesNotMatch(sourceOf(id), /google|tracking|pixel/i, id)
|
||||
}
|
||||
assert.deepEqual([...loadTemplate('K20').blocks], ['anfrage'])
|
||||
assert.deepEqual([...loadTemplate('K21').blocks].sort(), ['abgesagt', 'nach_frist', 'nicht_zugeordnet', 'verschoben', 'widerrufen'])
|
||||
for (const p of ['alt_datum', 'alt_zeit', 'eingang']) assert.ok(loadTemplate('K21').placeholders.includes(p), `K21: ${p}`)
|
||||
|
||||
const t20 = loadTemplate('K20')
|
||||
const werte20 = { ...sampleValues(t20), kunde_name: 'Berta', leistung: 'Herrenschnitt', datum: '12.10.2026', zeit: '10:00', gast_name: 'Max <b>Muster</b>', gast_email: 'max@example.com', gast_telefon: '0170 1', gast_nachricht: 'Bitte\nFenster', portal_link: 'https://project.webklar.com/dashboard.html' }
|
||||
const buchung = renderMail('K20', werte20, {})
|
||||
assert.deepEqual(buchung.problems, [])
|
||||
assert.match(buchung.html, /Max <b>Muster<\/b>/)
|
||||
assert.match(buchung.html, /Bitte<br>Fenster/)
|
||||
assert.match(buchung.text, /E-Mail: max@example\.com/)
|
||||
assert.match(buchung.text, /Im Portal ansehen: https:\/\/project\.webklar\.com\/dashboard\.html/)
|
||||
assert.doesNotMatch(buchung.text, /noch nicht bestätigt/)
|
||||
assert.match(renderMail('K20', werte20, { anfrage: true }).text, /Diese Anfrage ist noch nicht bestätigt/)
|
||||
|
||||
const t21 = loadTemplate('K21')
|
||||
const werte21 = { ...sampleValues(t21), alt_datum: '11.10.2026', alt_zeit: '09:00', datum: '12.10.2026', zeit: '10:00', eingang: '02.10.2026, 10:07 Uhr' }
|
||||
const fall = (block) => renderMail('K21', werte21, { [block]: true })
|
||||
assert.match(fall('abgesagt').text, /hat den Termin abgesagt/)
|
||||
assert.match(fall('verschoben').text, /Bisher: 11\.10\.2026, 09:00 Uhr/)
|
||||
assert.match(fall('verschoben').text, /Neu: 12\.10\.2026, 10:00 Uhr/)
|
||||
assert.match(fall('widerrufen').text, /Eingegangen am: 02\.10\.2026, 10:07 Uhr/)
|
||||
assert.match(fall('widerrufen').text, /widerrufen/)
|
||||
assert.match(fall('nach_frist').text, /Widerrufsfrist war bei Eingang bereits abgelaufen/)
|
||||
assert.match(fall('nicht_zugeordnet').text, /keiner Buchung zuordnen/)
|
||||
// je Fall erscheint nur der eigene Abschnitt
|
||||
const SATZ = { abgesagt: 'hat den Termin abgesagt', verschoben: 'hat den Termin verschoben', widerrufen: 'hat den Vertrag widerrufen', nach_frist: 'Widerrufsfrist war bei Eingang bereits abgelaufen', nicht_zugeordnet: 'keiner Buchung zuordnen' }
|
||||
for (const block of Object.keys(SATZ)) {
|
||||
const mail = fall(block)
|
||||
assert.deepEqual(mail.problems, [], block)
|
||||
for (const [anderer, satz] of Object.entries(SATZ)) assert.equal(mail.text.includes(satz), anderer === block, `${block}: ${satz}`)
|
||||
}
|
||||
})
|
||||
Reference in new issue
Block a user