'use strict'; const test = require('node:test'); const assert = require('node:assert'); const fs = require('node:fs'); const path = require('node:path'); let JSDOM = null; try { ({ JSDOM } = require('jsdom')); } catch (e) { /* jsdom fehlt -> skip */ } const SRC = fs.readFileSync(path.join(__dirname, '../../app/static/szenarien.js'), 'utf8'); const TIP = 'Für diese Eintragsart nicht relevant'; const HTML = `
`; function load() { const dom = new JSDOM(`${HTML}`, { runScripts: 'outside-only' }); const w = dom.window; const processed = []; w.htmx = { process: (el) => processed.push(el.id) }; w.eval(SRC); w.FBSzenario.init(w.document); const d = w.document; return { w, a: d.getElementById('a'), z: d.getElementById('z'), processed }; } function f(form, name) { return form.querySelector(`[name="${name}"]`); } function art(w, form, wert) { const sel = form.querySelector('[name="kind"]'); sel.value = wert; w.FBSzenario.aenderungArt(sel); } test('Prozent: Wert und Zeitraum aktiv', { skip: !JSDOM }, () => { const { a } = load(); assert.equal(f(a, 'value').disabled, false); assert.equal(a.querySelector('.value-label').textContent, 'Prozentsatz (%)'); assert.equal(f(a, 'start_date').disabled, false); assert.equal(f(a, 'end_date').disabled, false); assert.equal(a.querySelector('.bis-label').textContent, 'Gültig bis'); }); test('Kürzung: Label Kürzung (€)', { skip: !JSDOM }, () => { const { w, a } = load(); art(w, a, 'absolute'); assert.equal(a.querySelector('.value-label').textContent, 'Kürzung (€)'); }); test('Neuer Betrag: Ziel-Typ fest auf Posten, Kategorie gesperrt', { skip: !JSDOM }, () => { const { w, a } = load(); art(w, a, 'set'); const typ = f(a, 'target_type'); assert.equal(typ.value, 'recurring'); assert.equal(typ.querySelector('option[value="category"]').disabled, true); assert.equal(a.querySelector('.mod-target-recurring select').disabled, false); assert.equal(a.querySelector('.mod-target-category select').disabled, true); assert.equal(a.querySelector('.value-label').textContent, 'Neuer Betrag (€)'); art(w, a, 'percent'); assert.equal(typ.querySelector('option[value="category"]').disabled, false); }); test('Ende: Gültig ab und Wert gesperrt, Label Endet am', { skip: !JSDOM }, () => { const { w, a } = load(); art(w, a, 'ende'); assert.equal(f(a, 'start_date').disabled, true); assert.equal(f(a, 'start_date').title, TIP); assert.equal(f(a, 'value').disabled, true); assert.equal(f(a, 'end_date').disabled, false); assert.equal(a.querySelector('.bis-label').textContent, 'Endet am'); }); test('Entfällt: Wert gesperrt, Zeitraum aktiv', { skip: !JSDOM }, () => { const { w, a } = load(); art(w, a, 'remove'); assert.equal(f(a, 'value').disabled, true); assert.equal(a.querySelector('.value-label').textContent, 'Wert'); assert.equal(f(a, 'start_date').disabled, false); assert.equal(a.querySelector('.bis-label').textContent, 'Gültig bis'); }); test('Zahlung: Einmal → Wiederkehrend → Einmal', { skip: !JSDOM }, () => { const { w, z, processed } = load(); const sel = z.querySelector('.zahlung-art'); const wiederkehrend = ['rhythm', 'due_day', 'start_date', 'end_date']; assert.equal(z.getAttribute('hx-post'), '/api/scenarios/1/planned'); assert.equal(f(z, 'due').disabled, false); wiederkehrend.forEach((n) => assert.equal(f(z, n).disabled, true, n)); sel.value = 'wiederkehrend'; w.FBSzenario.zahlungArt(sel); assert.equal(z.getAttribute('hx-post'), '/api/scenarios/1/recurring'); assert.equal(f(z, 'due').disabled, true); assert.equal(f(z, 'due').title, TIP); wiederkehrend.forEach((n) => assert.equal(f(z, n).disabled, false, n)); sel.value = 'einmal'; w.FBSzenario.zahlungArt(sel); assert.equal(z.getAttribute('hx-post'), '/api/scenarios/1/planned'); wiederkehrend.forEach((n) => assert.equal(f(z, n).disabled, true, n)); ['name', 'amount', 'category_id'].forEach((n) => assert.equal(f(z, n).disabled, false, n)); assert.ok(processed.includes('z')); });