Files
Webklar-Kundenbereich/test/knAnsichtGutschrift.test.js
T
2026-10-16 17:11:15 +00:00

64 lines
7.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { test } from 'node:test'
import assert from 'node:assert/strict'
import { readFileSync } from 'node:fs'
import { createHash } from 'node:crypto'
import { zeigeGutschrift, sammleDateien, IO } from '../public/neu/ansicht-gutschrift.js'
import { sichtbarerText, ladeAlteApp } from './support/knWortlautOrakel.js'
import { mit, me, abo, aboAntwort, anfrageGutschrift, neueWurzel, LIMITS } from './support/knDaten.js'
const alt = ladeAlteApp(); const ABO = aboAntwort({ subscription: abo() })
const ANTRAEGE = { requests: [anfrageGutschrift({ id: 't1', status: 'rueckfrage', question: 'Bitte <b>Kündigungsbestätigung</b> hochladen' }), anfrageGutschrift({ id: 't2', status: 'genehmigt', amountCents: 4000, decisionNote: 'Passt.' }), anfrageGutschrift({ id: 't3', status: 'abgelehnt', decisionNote: 'Nicht erstattbar.' })], conditionsVersion: '2026-09-30', limits: LIMITS }
const SRV = { 'GET /api/abo': ABO, 'GET /api/abo/takeover-credits': ANTRAEGE }
const zeigeNeu = async (fx, m = me()) => { const w = neueWurzel(fx); await zeigeGutschrift(w, { route: { bereich: 'vertraege', etage: 'gutschrift', query: '' }, me: m, nav: 'push' }); await fx.ruhe(); return w }
for (const [name, abo_, antwort] of [['mit Anträgen', ABO, ANTRAEGE], ['ohne Abo', aboAntwort(), { requests: [], limits: LIMITS }]]) {
test(`Gutschrift (${name}): Karte wie in app.js`, mit({ 'GET /api/abo': abo_, 'GET /api/abo/takeover-credits': antwort }, async (fx) => {
const w = await zeigeNeu(fx)
assert.equal(sichtbarerText(fx.finde(w, '[data-karte="gutschrift"]')), sichtbarerText(await alt.gutschrift(abo_, antwort)))
}))
}
test('Bedingungen der Gutschrift: Block gleich dem Pin in legalTexts.test.js (Fassung 2026-09-30)', () => {
const q = readFileSync(new URL('../public/neu/ansicht-gutschrift.js', import.meta.url), 'utf8'); const i = q.indexOf('const TAKEOVER_CONDITIONS'); const block = q.slice(i, q.indexOf(']', i))
assert.equal(createHash('sha256').update(block).digest('hex'), '2b7a745cb599c0ab28f20615a745bd86da6faa8d120391ca56beac35a0473e62')
})
test('sammleDateien: Prüftexte wörtlich', async () => {
const g = { maxFiles: 3, maxFileBytes: 8 * 1048576, maxTotalBytes: 10 * 1048576 }; const f = (name, size) => ({ name, size }); const lies = async () => 'QQ=='
await assert.rejects(sammleDateien([], g, { erforderlich: true }, lies), { message: 'Bitte laden Sie die Rechnung Ihres bisherigen Anbieters hoch.' })
await assert.rejects(sammleDateien([1, 2, 3, 4].map((n) => f(`${n}.pdf`, 1)), g, { erforderlich: false }, lies), { message: 'Bitte höchstens 3 Dateien auf einmal hochladen.' })
await assert.rejects(sammleDateien([f('groß.pdf', 9 * 1048576)], g, { erforderlich: false }, lies), { message: '„groß.pdf“ ist größer als 8 MB.' })
await assert.rejects(sammleDateien([f('a.pdf', 6 * 1048576), f('b.pdf', 6 * 1048576)], g, { erforderlich: false }, lies), { message: 'Die Dateien sind zusammen größer als 10 MB.' })
assert.deepEqual(await sammleDateien([f('a.pdf', 5)], g, { erforderlich: true }, lies), [{ name: 'a.pdf', data: 'QQ==' }])
})
test('Antrag: Prüfungen wörtlich, Body mit denselben Schlüsseln wie früher, Meldung nach Erfolg', mit({ ...SRV, 'POST /api/abo/takeover-credits': {} }, async (fx) => {
IO.lies = async () => 'QQ=='; const w = await zeigeNeu(fx); await fx.klick(fx.finde(w, (e) => e.textContent === 'Gutschrift beantragen'))
await fx.klick(fx.finde(w, '#tk-submit')); assert.match(fx.text(w), /Bitte wählen Sie, welche Leistung Sie bisher woanders bezahlt haben\./)
await fx.klick(fx.finde(w, 'input[value="domain"]')); await fx.setze(fx.finde(w, '#tk-provider'), 'IONOS'); await fx.setze(fx.finde(w, '#tk-amount'), '119.88'); await fx.setze(fx.finde(w, '#tk-months'), '12'); await fx.setze(fx.finde(w, '#tk-paid-until'), '2027-03-31')
await fx.klick(fx.finde(w, '#tk-submit')); assert.match(fx.text(w), /Bitte bestätigen Sie Ihre Angaben und die Bedingungen\./)
fx.finde(w, '#tk-files').files = [{ name: 'r.pdf', size: 10 }]; await fx.klick(fx.finde(w, '#tk-consent')); await fx.klick(fx.finde(w, '#tk-submit')); await fx.ruhe()
assert.deepEqual(fx.fetchLog.find((a) => a.method === 'POST').body, { services: ['domain'], provider: 'IONOS', domain: '', invoiceAmount: '119.88', billingMonths: 12, paidUntil: '2027-03-31', message: '', email: 'anna@example.com', consent: true, files: [{ name: 'r.pdf', data: 'QQ==' }] })
assert.match(fx.text(w), /Vielen Dank! Ihr Antrag ist eingegangen\. Die Eingangsbestätigung haben wir an anna@example\.com geschickt; unsere Antwort kommt ebenfalls per E-Mail\./)
}))
test('Rückfrage beantworten; Kundentext bleibt Text; Ansichtsmodus sperrt alles', mit({ ...SRV, 'POST /api/abo/takeover-credits/t1/reply': {} }, async (fx) => {
const w = await zeigeNeu(fx); assert.equal(fx.finde(w, 'b'), null)
await fx.setze(fx.finde(w, 'form[data-reply-for="t1"] textarea'), 'Anbei.'); await fx.klick(fx.finde(w, 'form[data-reply-for="t1"] button[type="submit"]')); await fx.ruhe()
assert.deepEqual(fx.fetchLog.find((a) => a.url.endsWith('/reply')).body, { message: 'Anbei.', files: [] })
const v = await zeigeNeu(fx, me({ viewAs: true })); assert.match(fx.text(v), /Im Ansichtsmodus kann kein Antrag gestellt werden\./)
assert.ok(fx.alle(v, 'button').filter((b) => ['Gutschrift beantragen', 'Antwort senden'].includes(b.textContent)).every((b) => b.hasAttribute('disabled')))
}))
test('Gutschrift ohne Abo: Satz und Link zum Abo über die Brücke', mit({ 'GET /api/abo': aboAntwort(), 'GET /api/abo/takeover-credits': { requests: [], limits: LIMITS } }, async (fx) => {
const w = await zeigeNeu(fx); assert.match(fx.text(w), /Die Übernahmegutschrift können Sie beantragen, sobald Ihr Abo läuft\./)
const a = fx.finde(w, 'a[href="#vertraege"]'); assert.deepEqual([a.textContent, a.getAttribute('data-view')], ['Zum Abo', 'vertraege'])
}))
test('Gutschrift: Antwort ohne Text und Nachweis wird abgewiesen, Abbrechen schließt das Formular, Ausfälle haben eigene Texte', mit({ ...SRV, 'POST /api/abo/takeover-credits/t1/reply': {} }, async (fx) => {
const w = await zeigeNeu(fx)
await fx.klick(fx.finde(w, 'form[data-reply-for="t1"] button[type="submit"]')); await fx.ruhe()
assert.match(fx.text(w), /Bitte schreiben Sie eine Antwort oder laden Sie einen Nachweis hoch\./); assert.ok(!fx.fetchLog.some((a) => a.url.endsWith('/reply')))
assert.equal(fx.finde(w, '#tk-form').hasAttribute('hidden'), true); await fx.klick(fx.finde(w, '#tk-start')); assert.equal(fx.finde(w, '#tk-form').hasAttribute('hidden'), false)
await fx.klick(fx.finde(w, '#tk-cancel')); assert.equal(fx.finde(w, '#tk-form').hasAttribute('hidden'), true)
assert.match(fx.text(w), /Antrag .* · Domain/); assert.match(fx.text(w), /Nicht genehmigt/); assert.match(fx.text(w), /Gutschrift: 40,00 € – wird mit Ihren nächsten Monatsgebühren verrechnet\./)
}))
test('Gutschrift: Ausfall der Anträge und des Abos', mit({ 'GET /api/abo': ABO, 'GET /api/abo/takeover-credits': () => ({ status: 500, body: { error: 'Server kaputt' } }) }, async (fx) => {
assert.match(fx.text(await zeigeNeu(fx)), /Übernahmegutschrift konnte nicht geladen werden: Server kaputt/)
fx.tabelle['GET /api/abo'] = () => ({ status: 500, body: { error: 'x' } })
assert.match(fx.text(await zeigeNeu(fx)), /Deine Verträge konnten gerade nicht geladen werden\./)
}))