import { test } from 'node:test'; import assert from 'node:assert/strict'; import { validateRequest, applySwap, roleOn, openSlotFor, canTake } from '../server/requests.js'; const persons = [{ id: 'a', active: true }, { id: 'b', active: true }, { id: 'c', active: true }, { id: 'x', active: false }, { id: 'm', active: true, canMain: true, canCo: false }]; const plan = () => ({ '2026-10-05': { main: 'a', co: 'b', locked: false }, '2026-10-06': { main: 'c', co: 'a', locked: false }, '2026-10-07': { main: 'b', co: 'c', locked: false }, '2026-10-08': { off: true, main: null, co: null }, '2026-10-09': { main: null, co: 'c', locked: false }, '2026-10-12': { main: 'b', co: null, locked: false }, }); test('roleOn', () => { const p = plan(); assert.equal(roleOn(p['2026-10-05'], 'a'), 'main'); assert.equal(roleOn(p['2026-10-05'], 'b'), 'co'); assert.equal(roleOn(p['2026-10-05'], 'c'), null); assert.equal(roleOn(p['2026-10-08'], 'a'), null); assert.equal(roleOn(undefined, 'a'), null); }); test('validateRequest prüft Person, Tag, Einteilung und Partner', () => { const p = plan(); assert.match(validateRequest({}, persons, p).error, /Namen/); assert.match(validateRequest({ personId: 'x', date: '2026-10-05' }, persons, p).error, /Namen/); assert.match(validateRequest({ personId: 'a', date: 'gestern' }, persons, p).error, /Ungültiger Tag/); assert.match(validateRequest({ personId: 'c', date: '2026-10-05' }, persons, p).error, /nicht eingeteilt/); assert.match(validateRequest({ personId: 'a', date: '2026-10-05', partnerId: 'a' }, persons, p).error, /selbst/); assert.match(validateRequest({ personId: 'a', date: '2026-10-05', partnerDate: '2026-10-07' }, persons, p).error, /kein Platz frei/); assert.match(validateRequest({ personId: 'a', date: '2026-10-05', partnerDate: '2026-10-08' }, persons, p).error, /kein Meeting/); assert.match(validateRequest({ personId: 'a', date: '2026-10-05', partnerDate: '2026-10-06' }, persons, p).error, /schon eingeteilt/); const open = validateRequest({ personId: 'a', date: '2026-10-05', partnerDate: '2026-10-09' }, persons, p); assert.deepEqual(open.request, { personId: 'a', date: '2026-10-05', role: 'main', partnerId: null, partnerDate: '2026-10-09', note: '' }); assert.match(validateRequest({ personId: 'a', date: '2026-10-05', partnerId: 'b', partnerDate: '2026-10-05' }, persons, p).error, /derselbe/); const ok = validateRequest({ personId: 'a', date: '2026-10-05', partnerId: 'c', partnerDate: '2026-10-07', note: ' Zahnarzt ' }, persons, p); assert.deepEqual(ok.request, { personId: 'a', date: '2026-10-05', role: 'main', partnerId: 'c', partnerDate: '2026-10-07', note: 'Zahnarzt' }); const minimal = validateRequest({ personId: 'b', date: '2026-10-05' }, persons, p); assert.deepEqual(minimal.request, { personId: 'b', date: '2026-10-05', role: 'co', partnerId: null, partnerDate: null, note: '' }); }); test('applySwap über Kreuz', () => { const p = plan(); const { changes } = applySwap(p, { personId: 'a', date: '2026-10-05', partnerId: 'c', partnerDate: '2026-10-07' }); assert.equal(p['2026-10-05'].main, 'c'); assert.equal(p['2026-10-07'].co, 'a'); assert.equal(changes.length, 2); }); test('applySwap: Partner übernimmt den Tag', () => { const p = plan(); applySwap(p, { personId: 'b', date: '2026-10-05', partnerId: 'c', partnerDate: null }); assert.deepEqual([p['2026-10-05'].main, p['2026-10-05'].co], ['a', 'c']); }); test('openSlotFor und canTake beachten Rollen', () => { const p = plan(); assert.equal(openSlotFor(p['2026-10-09'], { id: 'a', canMain: true, canCo: true }), 'main'); assert.equal(openSlotFor(p['2026-10-12'], { id: 'a', canMain: true, canCo: true }), 'co'); assert.equal(openSlotFor(p['2026-10-12'], { id: 'm', canMain: true, canCo: false }), null, 'Nur-Haupt bekommt keinen Neben-Platz'); assert.equal(openSlotFor(p['2026-10-09'], { id: 'c', canMain: true, canCo: true }), null, 'schon eingeteilt'); assert.equal(openSlotFor(p['2026-10-05'], { id: 'c', canMain: true, canCo: true }), null, 'voll'); assert.ok(canTake({ id: 'm', canMain: true, canCo: false }, 'main') && !canTake({ id: 'm', canMain: true, canCo: false }, 'co')); assert.ok(!canTake({ id: 'x', active: false }, 'main')); }); test('applySwap: offenen Platz übernehmen, alter Platz wird frei gemeldet', () => { const p = plan(); const { changes, vacated } = applySwap(p, { personId: 'a', date: '2026-10-05', partnerId: null, partnerDate: '2026-10-09' }, persons); assert.equal(p['2026-10-09'].main, 'a'); assert.equal(p['2026-10-05'].main, null); assert.deepEqual(vacated, { date: '2026-10-05', role: 'main' }); assert.equal(changes.length, 2); assert.throws(() => applySwap(plan(), { personId: 'a', date: '2026-10-05', partnerId: null, partnerDate: '2026-10-07' }, persons), /kein passender Platz/); }); test('applySwap prüft Rollen der Beteiligten', () => { const p = plan(); // m darf keine Nebenmoderation: Übernahme von b's Neben-Platz am 05.10. scheitert assert.throws(() => applySwap(p, { personId: 'b', date: '2026-10-05', partnerId: 'm', partnerDate: null }, persons), /keine Nebenmoderation/); assert.equal(p['2026-10-05'].co, 'b', 'nichts verändert'); }); test('applySwap lehnt unmögliche Fälle verständlich ab', () => { assert.throws(() => applySwap(plan(), { personId: 'a', date: '2026-10-05', partnerId: null }), /Wunschpartner oder Wunschtag/); assert.throws(() => applySwap(plan(), { personId: 'c', date: '2026-10-05', partnerId: 'b' }), /nicht mehr eingeteilt/); assert.throws(() => applySwap(plan(), { personId: 'a', date: '2026-10-05', partnerId: 'b' }), /andere Moderation/); assert.throws(() => applySwap(plan(), { personId: 'a', date: '2026-10-05', partnerId: 'c', partnerDate: '2026-10-08' }), /am Wunschtag nicht eingeteilt/); assert.throws(() => applySwap(plan(), { personId: 'a', date: '2026-10-05', partnerId: 'c', partnerDate: '2026-10-06' }), /anfragende Person/); });