Terminplaner: Fix Widerruf nach Terminbeginn, Zustimmung beim Verschieben, Berliner Widerrufsfrist, Grenzen nur ohne Treffer

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-03 08:17:43 +00:00
1 parent 2d9b75b3bf
commit c4ec24448e
10 files changed
+319 -77

No files matched your search

+178 -23
View File
@@ -639,6 +639,58 @@ test('verschiebeGast: eine fuer die alte Zeit gesendete Erinnerung wird zurueckg
assert.equal(buchung(keine.id).erinnerungGesendetAt ?? null, null)
})
test('verschiebeGast: ohne Zustimmung zum vorzeitigen Beginn nicht in die Widerrufsfrist einer kostenpflichtigen Verbraucherbuchung (R28)', async () => {
const plan = { 1: [['09:00', '18:00']], 2: [['09:00', '18:00']] }
const ctx = await speichere(einstellung({ ressourcen: [{ id: R1, name: 'Anna', plan }, { id: R2, name: 'Ben', plan }] }))
const a = await gebucht(ctx) // Mo 26.10. 10:00, Vertrag Mo 05.10. => Fristende Mo 19.10.; 21 Tage Vorlauf: keine Zustimmung noetig gewesen
assert.equal(JSON.parse(a.buchung.nachweis).vorzeitig, undefined)
const standVorher = claimsStand()
const docVorher = JSON.stringify(buchung(a.id))
const mails = sink.sent.length
// innerhalb der Frist (auch am letzten Tag, 17:00 Uhr): 409, nichts aendert sich
for (const [tag, zeit] of [['2026-10-12', '11:00'], ['2026-10-19', '17:00']]) {
const err = await fehlerVon(() => verschiebeGast(a.verwaltung, { tag, zeit }, JETZT))
assert.equal(err.status, 409, `${tag} ${zeit}`)
assert.equal(err.code, 'zustimmung_noetig')
assert.deepEqual(err.fehler, { _: 'Dieser Termin liegt innerhalb der Widerrufsfrist. Bitte neu buchen oder anrufen: 06301 1234.' })
}
assert.equal(claimsStand(), standVorher)
assert.equal(JSON.stringify(buchung(a.id)), docVorher)
assert.equal(sink.sent.length, mails)
assert.equal(eintraege().filter((d) => d.art === 'G07').length, 0)
// am Tag nach dem Fristende geht es
const erg = await verschiebeGast(a.verwaltung, { tag: '2026-10-20', zeit: '09:00' }, JETZT)
assert.deepEqual(erg.termin, { datum: 'Dienstag, 20.10.2026', zeit: '09:00' })
assert.equal(iso(buchung(a.id).startsAt), '2026-10-20T07:00:00.000Z')
// mit der Zustimmung zum vorzeitigen Beginn (beim Buchen gegeben) ist es erlaubt
const b = await gebucht(ctx, { ...NAH, zeit: '12:00', email: 'zwei@example.com' })
assert.ok(JSON.parse(b.buchung.nachweis).vorzeitig)
await verschiebeGast(b.verwaltung, { tag: '2026-10-19', zeit: '17:00' }, JETZT)
assert.equal(iso(buchung(b.id).startsAt), '2026-10-19T15:00:00.000Z')
// ohne Preis, als Unternehmer oder bei einer Anfrage gilt die Regel nicht
const frei = await speichere(
einstellung({
ressourcen: [{ id: R1, name: 'Anna', plan }, { id: R2, name: 'Ben', plan }],
leistungen: [...eingabeEinstellung().leistungen, { id: 's_bbbbbbb3', name: 'Kennenlernen', dauer: 30, preisArt: 'keiner', buchungsart: 'sofort', ressourcen: [R1, R2] }],
}),
)
const gratis = await gebucht(frei, { leistung: 's_bbbbbbb3', zeit: '14:00', email: 'drei@example.com' })
await verschiebeGast(gratis.verwaltung, { tag: '2026-10-12', zeit: '11:00' }, JETZT)
assert.equal(iso(buchung(gratis.id).startsAt), '2026-10-12T09:00:00.000Z')
const anfrage = await gebucht(frei, { leistung: S_ANFRAGE, zeit: '16:00', email: 'vier@example.com' })
await verschiebeGast(anfrage.verwaltung, { tag: '2026-10-12', zeit: '15:00' }, JETZT)
assert.equal(iso(buchung(anfrage.id).startsAt), '2026-10-12T13:00:00.000Z')
const unternehmer = await speichere(einstellung({ ressourcen: [{ id: R1, name: 'Anna', plan }, { id: R2, name: 'Ben', plan }], recht: { gaesteSind: 'unternehmer', freizeit: false } }))
const u = await gebucht(unternehmer, { zeit: '16:00', email: 'fuenf@example.com' })
assert.equal(u.buchung.verbraucher, false)
await verschiebeGast(u.verwaltung, { tag: '2026-10-12', zeit: '09:00' }, JETZT)
assert.equal(iso(buchung(u.id).startsAt), '2026-10-12T07:00:00.000Z')
})
test('verschiebeGast: Token, Modus und Uhr werden geprueft; abgesagte Termine lassen sich nicht verschieben', async () => {
const ctx = await speichere()
const { id, verwaltung, token } = await gebucht(ctx)
@@ -708,10 +760,11 @@ test('zeitenFuerToken: Eingaben, Token, Frist und Uhr', async () => {
// ---------------------------------------------------------------- Widerruf per Link
test('kannWiderrufen: sofort ab bestaetigtAt, angenommene Anfrage ab angenommenAt; 14 Tage, Beginn, Verbraucher, Handeintrag', () => {
test('kannWiderrufen: sofort ab bestaetigtAt, angenommene Anfrage ab angenommenAt; Fristende, Beginn, Verbraucher, Handeintrag', () => {
const basis = { buchungsart: 'sofort', verbraucher: true, status: 'bestaetigt', quelle: 'online', bestaetigtAt: iso(JETZT), startsAt: iso(plus(JETZT, 30 * TAG_MS)) }
assert.equal(kannWiderrufen(basis, plus(JETZT, 14 * TAG_MS - 1)), true)
assert.equal(kannWiderrufen(basis, plus(JETZT, 14 * TAG_MS)), false)
// Vertrag Montag 05.10.: Fristende Montag 19.10., 23:59:59,999 Uhr Berliner Zeit (MESZ) = 21:59:59,999 UTC
assert.equal(kannWiderrufen(basis, new Date('2026-10-19T21:59:59.999Z')), true)
assert.equal(kannWiderrufen(basis, new Date('2026-10-19T22:00:00.000Z')), false)
assert.equal(kannWiderrufen(basis, plus(new Date(basis.startsAt), 0)), false, 'Termin hat begonnen')
assert.equal(kannWiderrufen({ ...basis, startsAt: iso(plus(JETZT, 3 * TAG_MS)) }, plus(JETZT, 3 * TAG_MS - 1)), true, 'bis zum Beginn')
assert.equal(kannWiderrufen({ ...basis, verbraucher: false }, JETZT), false)
@@ -722,12 +775,36 @@ test('kannWiderrufen: sofort ab bestaetigtAt, angenommene Anfrage ab angenommenA
const anfrage = { ...basis, buchungsart: 'anfrage', bestaetigtAt: undefined, angenommenAt: iso(plus(JETZT, 2 * TAG_MS)) }
assert.equal(kannWiderrufen(anfrage, plus(JETZT, 3 * TAG_MS)), true, 'angenommene Anfrage')
assert.equal(kannWiderrufen(anfrage, plus(JETZT, 16 * TAG_MS - 1)), true, 'die Frist zaehlt ab der Annahme')
assert.equal(kannWiderrufen(anfrage, plus(JETZT, 16 * TAG_MS)), false)
// Annahme Mittwoch 07.10.: Fristende Mittwoch 21.10. (21:59:59,999 UTC)
assert.equal(kannWiderrufen(anfrage, new Date('2026-10-21T21:59:59.999Z')), true, 'die Frist zaehlt ab der Annahme')
assert.equal(kannWiderrufen(anfrage, new Date('2026-10-21T22:00:00.000Z')), false)
assert.equal(kannWiderrufen({ ...anfrage, angenommenAt: undefined }, JETZT), false, 'ohne Annahme kein Vertrag')
assert.equal(kannWiderrufen({ ...anfrage, bestaetigtAt: iso(JETZT), angenommenAt: undefined }, JETZT), false, 'bestaetigtAt allein macht eine Anfrage nicht verbindlich')
})
test('kannWiderrufen: Fristende nach §§ 187, 188, 193 BGB im Berliner Kalender - Zeitumstellung, Wochenende, Feiertag, Tageswechsel', () => {
const buchungAm = (vertrag) => ({ buchungsart: 'sofort', verbraucher: true, status: 'bestaetigt', quelle: 'online', bestaetigtAt: vertrag, startsAt: '2027-02-01T09:00:00.000Z' })
const grenze = (vertrag, letzterMoment) => {
const b = buchungAm(vertrag)
const ende = new Date(letzterMoment)
assert.equal(kannWiderrufen(b, ende), true, `${vertrag}: noch ${letzterMoment}`)
assert.equal(kannWiderrufen(b, new Date(ende.getTime() + 1)), false, `${vertrag}: nach ${letzterMoment} nicht mehr`)
}
// Sommerzeit endet am 25.10.: Vertrag Montag 12.10. 10:00 MESZ => letzter Tag Montag 26.10. (MEZ), 23:59:59,999 = 22:59:59,999 UTC.
// (14 x 24 Stunden wuerden schon am 26.10. um 08:00 UTC enden)
grenze('2026-10-12T08:00:00.000Z', '2026-10-26T22:59:59.999Z')
// Sommerzeit beginnt am 29.03.: Vertrag Montag 16.03. 10:00 MEZ => letzter Tag Montag 30.03. (MESZ), 21:59:59,999 UTC
grenze('2026-03-16T09:00:00.000Z', '2026-03-30T21:59:59.999Z')
// der 14. Tag ist ein Samstag (24.10.) => Montag 26.10.; der Sonntag dazwischen zaehlt noch mit
grenze('2026-10-10T10:00:00.000Z', '2026-10-26T22:59:59.999Z')
assert.equal(kannWiderrufen(buchungAm('2026-10-10T10:00:00.000Z'), new Date('2026-10-25T10:00:00.000Z')), true)
// der 14. Tag ist Freitag, 25.12. (Feiertag), danach Samstag 26.12. (Feiertag) und Sonntag => Montag 28.12.
grenze('2026-12-11T10:00:00.000Z', '2026-12-28T22:59:59.999Z')
// Vertrag um 23:30 MESZ am 05.10. (21:30 UTC) zaehlt noch fuer den 05.10., um 00:30 MESZ am 06.10. (22:30 UTC am 05.10.) fuer den 06.10.
grenze('2026-10-05T21:30:00.000Z', '2026-10-19T21:59:59.999Z')
grenze('2026-10-05T22:30:00.000Z', '2026-10-20T21:59:59.999Z')
})
test('widerrufeGast: 2 Stunden vor dem Termin trotz abgelaufener Stornofrist; abgesagt von gast, Zellen frei, G08 zugeordnet, K21 widerrufen', async () => {
const ctx = await speichere()
const { id, buchung: b, verwaltung, mailStart } = await gebucht(ctx, NAH)
@@ -770,19 +847,20 @@ test('widerrufeGast: Eingang in Berliner Zeit (22:30 UTC = 00:30 am Folgetag)',
assert.deepEqual(erg, { eingang: { datum: '11.10.2026', uhrzeit: '00:30' } })
})
test('widerrufeGast: die 14 Tage gelten ab der Bestaetigung; am letzten Moment wirksam, danach nur gespeichert und gemeldet (nach_frist)', async () => {
test('widerrufeGast: die Frist gilt ab der Bestaetigung bis Fristende; am letzten Moment wirksam, danach nur gespeichert und gemeldet (nach_frist)', async () => {
const ctx = await speichere()
const a = await gebucht(ctx) // Termin 21 Tage nach der Buchung
const b = await gebucht(ctx, { zeit: '12:00', email: 'zwei@example.com' })
const vorher = sink.sent.length
await widerrufeGast(a.verwaltung, { name: 'Max' }, plus(JETZT, 14 * TAG_MS - 1))
// Vertrag Montag 05.10. => Fristende Montag 19.10., 23:59:59,999 MESZ
const fristEnde = new Date('2026-10-19T21:59:59.999Z')
assert.deepEqual(await widerrufeGast(a.verwaltung, { name: 'Max' }, fristEnde), { eingang: { datum: '19.10.2026', uhrzeit: '23:59' } })
assert.equal(buchung(a.id).status, 'abgesagt')
const spaet = plus(JETZT, 14 * TAG_MS)
const erg = await widerrufeGast(b.verwaltung, { name: 'Erika Beispiel' }, spaet)
const erg = await widerrufeGast(b.verwaltung, { name: 'Erika Beispiel' }, plus(fristEnde, 1))
await warteAufVersand()
assert.deepEqual(erg, { eingang: { datum: '19.10.2026', uhrzeit: '10:00' } })
assert.deepEqual(erg, { eingang: { datum: '20.10.2026', uhrzeit: '00:00' } })
const nachher = buchung(b.id)
assert.equal(nachher.status, 'bestaetigt', 'der Termin bleibt')
assert.equal(nachher.widerrufenAt, undefined)
@@ -799,6 +877,54 @@ test('widerrufeGast: die 14 Tage gelten ab der Bestaetigung; am letzten Moment w
assert.equal(an(neu, 'info@salon.de').find((m) => /nach Ablauf/i.test(m.subject)).subject, 'Widerruf nach Ablauf der Frist: Damenschnitt am 26.10.2026 um 12:00')
})
test('Widerruf nach Terminbeginn bei noch laufender Frist (R27): vermerkt, G08 ohne "abgelaufen", K21 begonnen, Termin bleibt; nach Fristende nach_frist', async () => {
const ctx = await speichere()
const a = await gebucht(ctx, NAH) // 12.10.2026 10:00 MESZ, Vertrag 05.10.: die Frist laeuft bis 19.10.
const b = await gebucht(ctx, { ...NAH, zeit: '12:00', email: 'zwei@example.com' })
const antwortA = { eingang: { datum: '12.10.2026', uhrzeit: '10:20' } }
const vorher = sink.sent.length
// ohne Link, 20 Minuten nach Beginn
const jetztA = plus(new Date(a.buchung.startsAt), 20 * MIN)
assert.deepEqual(await widerrufeOhneLink(ctx, { name: 'Max Mustermann', email: 'max@example.com', nummer: buchungsNummer(a.id) }, jetztA), antwortA)
// mit Link, 10 Minuten nach Beginn
const jetztB = plus(new Date(b.buchung.startsAt), 10 * MIN)
assert.deepEqual(await widerrufeGast(b.verwaltung, { name: 'Erika Beispiel' }, jetztB), { eingang: { datum: '12.10.2026', uhrzeit: '12:10' } })
await warteAufVersand()
for (const [x, grund] of [[a, 'Max Mustermann'], [b, 'Erika Beispiel']]) {
const nachher = buchung(x.id)
assert.equal(nachher.status, 'bestaetigt', 'der Termin bleibt')
assert.equal(nachher.widerrufenAt, undefined)
assert.equal(claims(x.id).length, 10)
assert.match(nachher.absageGrund, /nach Terminbeginn/)
assert.ok(nachher.absageGrund.includes(grund))
}
const neu = sink.sent.slice(vorher)
assert.equal(neu.length, 4)
const g08 = an(neu, 'max@example.com')[0]
assert.equal(g08.subject, 'Eingangsbestätigung Ihres Widerrufs')
assert.match(g08.text, /12\.10\.2026, 10:20 Uhr/)
assert.match(g08.text, /prüft Ihre Erklärung und meldet sich bei Ihnen/)
assert.doesNotMatch(g08.text, /abgelaufen|Der Termin ist abgesagt/)
assert.ok(!g08.text.includes(buchungsNummer(a.id)), 'neutraler Satz, keine Zusage zur Buchung')
const k21 = an(neu, 'info@salon.de').find((m) => m.text.includes('max@example.com'))
assert.equal(k21.subject, 'Widerruf nach Terminbeginn: Damenschnitt am 12.10.2026 um 10:00')
assert.match(k21.text, /Ein Widerruf ist eingegangen, nachdem der Termin bereits begonnen hatte\./)
assert.match(k21.text, /wertersatz|Wertersatz/)
assert.doesNotMatch(k21.text, /Widerrufsfrist bei Eingang bereits abgelaufen/)
assert.equal(eintraege().filter((d) => d.art === 'G08').length, 2)
// nach Fristende (Montag 19.10., 23:59:59,999) dieselbe Erklaerung: jetzt wirklich nach der Frist
const vorher2 = sink.sent.length
await widerrufeOhneLink(ctx, { name: 'Max Mustermann', email: 'max@example.com', nummer: buchungsNummer(a.id) }, new Date('2026-10-19T22:00:00.000Z'))
await warteAufVersand()
const spaet = sink.sent.slice(vorher2)
assert.match(an(spaet, 'max@example.com')[0].text, /Widerrufsfrist bei Eingang Ihrer Erklärung bereits abgelaufen/)
assert.equal(an(spaet, 'info@salon.de')[0].subject, 'Widerruf nach Ablauf der Frist: Damenschnitt am 12.10.2026 um 10:00')
assert.match(buchung(a.id).absageGrund, /nach Ablauf der Frist/)
})
test('widerrufeGast: eine nicht angenommene Anfrage kann nicht widerrufen werden (409), nur absagen; ebenso Unternehmer', async () => {
const ctx = await speichere()
const anfrage = await gebucht(ctx, { leistung: S_ANFRAGE })
@@ -828,8 +954,9 @@ test('widerrufeGast: eine vom Betrieb angenommene Anfrage ist widerrufbar, die F
// Annahme durch den Betrieb (Aufgabe 14) von Hand nachgestellt
const angenommen = plus(JETZT, 2 * TAG_MS)
aw.seed('termineBookings', { ...b, status: 'bestaetigt', angenommenAt: iso(angenommen) })
assert.equal((await vorschau(verwaltung, plus(angenommen, 13 * TAG_MS))).aktionen.widerrufen, true)
assert.equal((await vorschau(verwaltung, plus(angenommen, 14 * TAG_MS))).aktionen.widerrufen, false)
const fristEnde = new Date('2026-10-21T21:59:59.999Z') // Annahme Mittwoch 07.10. => Fristende Mittwoch 21.10.
assert.equal((await vorschau(verwaltung, fristEnde)).aktionen.widerrufen, true)
assert.equal((await vorschau(verwaltung, plus(fristEnde, 1))).aktionen.widerrufen, false)
const jetzt = plus(angenommen, 13 * TAG_MS) // 20.10.2026, der Termin am 26.10. liegt noch in der Zukunft
const erg = await widerrufeGast(verwaltung, { name: 'Max' }, jetzt)
assert.ok(erg.eingang)
@@ -996,34 +1123,62 @@ test('widerrufeOhneLink: vierter G08 an dieselbe Adresse am Tag wird nicht gesen
assert.equal(eintraege().filter((d) => d.art === 'G08').length, 4)
})
test('widerrufeOhneLink: 20 G08 je Funktion und Stunde, 10 K21 nicht_zugeordnet je Funktion und Stunde; weitere werden still uebersprungen', async () => {
test('widerrufeOhneLink: 20 G08 je Funktion und Stunde, 30 K21 nicht_zugeordnet je Funktion und Stunde; weitere werden still uebersprungen', async () => {
const ctx = await speichere()
const antworten = []
for (let i = 0; i < 22; i += 1) antworten.push(await widerrufeOhneLink(ctx, { name: `Gast ${i}`, email: `gast${i}@example.com`, nummer: 'ZZZZZZZZ' }, JETZT))
for (let i = 0; i < 32; i += 1) antworten.push(await widerrufeOhneLink(ctx, { name: `Gast ${i}`, email: `gast${i}@example.com`, nummer: 'ZZZZZZZZ' }, JETZT))
await warteAufVersand()
for (const a of antworten) assert.deepEqual(a, antworten[0])
assert.equal(eintraege().filter((d) => d.art === 'G08').length, 20)
assert.equal(eintraege().filter((d) => d.art === 'K21').length, 10)
assert.equal(eintraege().filter((d) => d.art === 'K21').length, 30)
// eine Stunde spaeter beginnen beide Fenster neu
await widerrufeOhneLink(ctx, { name: 'Spaet', email: 'spaet@example.com', nummer: 'ZZZZZZZZ' }, plus(JETZT, 60 * MIN))
await warteAufVersand()
assert.equal(eintraege().filter((d) => d.art === 'G08').length, 21)
assert.equal(eintraege().filter((d) => d.art === 'K21').length, 11)
assert.equal(eintraege().filter((d) => d.art === 'K21').length, 31)
})
test('widerrufeOhneLink: Grenzen gelten auch fuer Treffer; bei erreichter G08-Grenze geht der Widerruf trotzdem durch', async () => {
test('widerrufeOhneLink: ein Treffer bekommt seine Mails immer und zaehlt nicht mit; die Grenzen gelten nur ohne Treffer (R30)', async () => {
const ctx = await speichere()
const { id } = await gebucht(ctx)
const a = await gebucht(ctx) // max@example.com
const anfrage = await gebucht(ctx, { leistung: S_ANFRAGE, zeit: '12:00', email: 'vier@example.com' }) // nicht angenommen: kein Widerrufsrecht
const g08 = () => eintraege().filter((d) => d.art === 'G08')
const k21 = () => eintraege().filter((d) => d.art === 'K21')
// Adresse max@ (3 Erklaerungen ins Leere), dann Funktion und K21-Grenze ausschoepfen
for (let i = 0; i < 3; i += 1) await widerrufeOhneLink(ctx, { name: 'Max', email: 'max@example.com', nummer: 'ZZZZZZZZ' }, JETZT)
for (let i = 0; i < 28; i += 1) await widerrufeOhneLink(ctx, { name: `Gast ${i}`, email: `gast${i}@example.com`, nummer: 'ZZZZZZZZ' }, JETZT)
await warteAufVersand()
assert.equal(eintraege().filter((d) => d.art === 'G08').length, 3)
const erg = await widerrufeOhneLink(ctx, { name: 'Max', email: 'max@example.com', nummer: buchungsNummer(id) }, plus(JETZT, MIN))
assert.equal(g08().length, 20, 'G08: Funktionsgrenze erreicht')
const kNichtZugeordnet = k21().length
assert.equal(kNichtZugeordnet, 30, 'K21 nicht_zugeordnet: Grenze erreicht')
const nochEine = await widerrufeOhneLink(ctx, { name: 'Noch', email: 'neu@example.com', nummer: 'ZZZZZZZZ' }, JETZT)
await warteAufVersand()
assert.equal(g08().length, 20, 'ohne Treffer bleibt die Grenze')
assert.equal(k21().length, 30)
// Treffer mit Widerrufsrecht: G08 (an die Adresse mit erschoepftem Tageskontingent) und K21 gehen trotzdem raus
const erg = await widerrufeOhneLink(ctx, { name: 'Max', email: 'max@example.com', nummer: buchungsNummer(a.id) }, plus(JETZT, MIN))
await warteAufVersand()
assert.deepEqual(erg, { eingang: { datum: '05.10.2026', uhrzeit: '10:01' } })
assert.equal(buchung(id).status, 'abgesagt', 'der Widerruf ist wirksam')
assert.equal(eintraege().filter((d) => d.art === 'G08').length, 3, 'aber keine vierte Bestaetigung')
assert.equal(eintraege().filter((d) => d.art === 'K21' && d.bookingId === id).length, 1, 'der Betrieb erfaehrt davon')
assert.deepEqual(nochEine, { eingang: { datum: '05.10.2026', uhrzeit: '10:00' } })
assert.equal(buchung(a.id).status, 'abgesagt', 'der Widerruf ist wirksam')
assert.equal(g08().length, 21)
assert.equal(g08().filter((d) => d.bookingId === a.id).length, 1)
assert.equal(k21().filter((d) => d.bookingId === a.id).length, 1, 'der Betrieb erfaehrt davon')
// Treffer ohne Widerrufsrecht (nicht angenommene Anfrage): G08 und K21 nicht_zugeordnet ebenfalls ohne Grenze
await widerrufeOhneLink(ctx, { name: 'Vier', email: 'vier@example.com', nummer: buchungsNummer(anfrage.id) }, plus(JETZT, 2 * MIN))
await warteAufVersand()
assert.equal(g08().length, 22)
assert.equal(k21().length, 32)
assert.equal(buchung(anfrage.id).status, 'angefragt', 'die Anfrage bleibt unveraendert')
// der Treffer hat nichts verbraucht: ohne Treffer bleibt es bei der Grenze, nach einer Stunde geht es wieder
await widerrufeOhneLink(ctx, { name: 'Max', email: 'max@example.com', nummer: 'ZZZZZZZZ' }, plus(JETZT, 3 * MIN))
await warteAufVersand()
assert.equal(g08().length, 22)
})
test('widerrufeOhneLink: Eingaben - Name und E-Mail Pflicht (400), sonst nichts gespeichert und keine Mail', async () => {