Files
Webklar-Kundenbereich/test/knAnsichtRechnungen.test.js
T
2026-10-16 17:00:28 +00:00

38 lines
4.2 KiB
JavaScript

import { test } from 'node:test'
import assert from 'node:assert/strict'
import { zeigeRechnungen } from '../public/neu/vertraege-rechnungen.js'
import { mit, me, rechnung, neueWurzel } from './support/knDaten.js'
import { eintrag } from './auftraegeKundenportalDaten.js'
test('Rechnungen: Zeilen, Links nur mit sicherer Adresse, Projekt bleibt Text', mit({ 'GET /api/invoices': { invoices: [
rechnung({ id: 'in_1', number: 'RE-2026-0042', amount: 50, balance: 50, status: 'Offen', portalUrl: 'https://invoice.stripe.com/i/x', hasPdf: true, projekt: 'Bäckerei <i>Roth</i>' }),
rechnung({ id: 'in_0', number: 'RE-2026-0030', amount: 20, balance: 0, paid: true, status: 'Bezahlt', portalUrl: 'javascript:alert(1)', hasPdf: true })], incomplete: false }, 'GET /api/auftraege': { aktiv: false } }, async (fx) => {
const box = neueWurzel(fx); await zeigeRechnungen(box, { me: me() }); await fx.ruhe()
const zeilen = fx.alle(box, 'tbody tr'); assert.equal(zeilen.length, 2); assert.match(zeilen[0].textContent, /50,00 €/); assert.equal(fx.finde(box, 'i'), null)
assert.deepEqual(fx.alle(zeilen[0], 'a').map((a) => [a.textContent, a.getAttribute('href')]), [['Zahlen', 'https://invoice.stripe.com/i/x'], ['PDF', '/api/invoices/in_1/pdf']])
assert.deepEqual(fx.alle(zeilen[1], 'a').map((a) => a.textContent), ['PDF'])
}))
let antwort
test('Rechnungen: Ausfall, leere Liste und unvollständige Antwort', mit({ 'GET /api/invoices': () => antwort, 'GET /api/auftraege': { aktiv: false } }, async (fx) => {
const zeige = async (a) => { antwort = a; const b = neueWurzel(fx); await zeigeRechnungen(b, { me: me() }); await fx.ruhe(); return fx.text(b) }
assert.match(await zeige({ status: 500, body: { error: 'Server kaputt' } }), /Rechnungen konnten nicht geladen werden: Server kaputt/)
assert.match(await zeige({ body: { invoices: [] } }), /Es liegen noch keine Rechnungen vor\./)
assert.match(await zeige({ body: { invoices: [rechnung({ balance: 0 })], incomplete: true } }), /Deine Rechnungen konnten gerade nicht vollständig geladen werden\. Bitte versuche es später noch einmal\./)
}))
test('Aufträge bestätigen: der POST-Body ist ein Objekt, kein JSON-String (Review Focus 1)', mit({ 'GET /api/invoices': { invoices: [] }, 'GET /api/auftraege': { aktiv: true, auftraege: [eintrag({ id: 'ab1' })] }, 'POST /api/auftraege/ab1/bestaetigen': () => ({ body: { auftrag: { ...eintrag({ id: 'ab1' }), status: 'bestaetigt' } } }) }, async (fx) => {
const box = neueWurzel(fx); await zeigeRechnungen(box, { me: me() }); await fx.ruhe()
await fx.klick(fx.finde(box, '[data-feld="bestaetigung"]')); await fx.klick(fx.finde(box, '[data-aktion="bestaetigen"]'))
const post = fx.fetchLog.find((a) => a.method === 'POST'); assert.equal(post.url, '/api/auftraege/ab1/bestaetigen'); assert.equal(typeof post.body, 'object')
assert.equal(fx.finde(box, '#kn-auftraege').classList.contains('hidden'), false)
}))
test('Aufträge im Ansichtsmodus: Häkchen gesperrt, Hinweis sichtbar, kein POST', mit({ 'GET /api/invoices': { invoices: [] }, 'GET /api/auftraege': { aktiv: true, auftraege: [eintrag({ id: 'ab1', kannBestaetigen: false })] } }, async (fx) => {
const box = neueWurzel(fx); await zeigeRechnungen(box, { me: me({ viewAs: true }) }); await fx.ruhe()
assert.ok(fx.finde(box, '[data-gesperrt]')); assert.equal(fx.finde(box, '[data-feld="bestaetigung"]').hasAttribute('disabled'), true); assert.deepEqual(fx.fetchLog.filter((a) => a.method === 'POST'), [])
}))
test('Rechnungen: schon geladene Antwort wird benutzt (kein zweiter Abruf), Aufträge-Ausfall stört nicht', mit({ 'GET /api/auftraege': () => ({ status: 500, body: { error: 'x' } }) }, async (fx) => {
const box = neueWurzel(fx)
await zeigeRechnungen(box, { me: me(), antwort: { invoices: [rechnung({ id: 'in_9', number: 'RE-9', balance: 10, overdue: true, status: 'Überfällig', portalUrl: 'https://invoice.stripe.com/i/y' })] } }); await fx.ruhe()
assert.ok(!fx.fetchLog.some((a) => a.url === '/api/invoices')); assert.match(fx.text(box), /RE-9/); assert.equal(fx.finde(box, '#kn-auftraege').classList.contains('hidden'), true)
const z = fx.finde(box, 'tbody tr'); assert.equal(fx.finde(z, 'td[data-label="Nr."]') !== null, true); assert.match(fx.finde(z, '.kn-pille').className, /kn-pille-rot/)
}))