Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
117 lines
5.5 KiB
JavaScript
117 lines
5.5 KiB
JavaScript
'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 = `
|
|
<form id="a" class="entry-form aenderung-form" hx-post="/api/scenarios/1/modifiers">
|
|
<select name="kind"><option value="percent">Prozent</option><option value="absolute">Kürzung (€)</option>
|
|
<option value="set">Neuer Betrag</option><option value="remove">Entfällt</option><option value="ende">Ende</option></select>
|
|
<select name="target_type"><option value="category">Kategorie</option><option value="recurring">Wiederkehrender Posten</option></select>
|
|
<span class="mod-target-category"><select name="target_id"><option value="1">K</option></select></span>
|
|
<span class="mod-target-recurring" style="display:none"><select name="target_id" disabled><option value="2">P</option></select></span>
|
|
<label><span class="value-label">Prozentsatz (%)</span><input name="value"></label>
|
|
<input type="date" name="start_date">
|
|
<label><span class="bis-label">Gültig bis</span><input type="date" name="end_date"></label>
|
|
</form>
|
|
<form id="z" class="entry-form zahlung-form" hx-post="/api/scenarios/1/planned"
|
|
data-planned-url="/api/scenarios/1/planned" data-recurring-url="/api/scenarios/1/recurring">
|
|
<select class="zahlung-art"><option value="einmal">Einmalzahlung</option><option value="wiederkehrend">Wiederkehrend</option></select>
|
|
<input name="name"><input name="amount"><select name="category_id"><option value="">(keine)</option></select>
|
|
<input type="date" name="due">
|
|
<select name="rhythm"><option value="monthly">monatlich</option></select>
|
|
<input name="due_day"><input type="date" name="start_date"><input type="date" name="end_date">
|
|
</form>`;
|
|
|
|
function load() {
|
|
const dom = new JSDOM(`<!doctype html><body>${HTML}</body>`, { 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'));
|
|
});
|