Ein Wunschtag ohne Tauschpartner bedeutet jetzt: die Person übernimmt dort einen offenen Platz; ihr alter Platz wird beim Ausführen sofort fair nachbesetzt, ohne sie selbst. Rollen werden bei allen Tauschformen geprüft. Bearbeiter können Person und Wunschtag einer Anfrage nachtragen, etwa aus der Notiz. Der Anfragedialog zeigt, was am Wunschtag los ist. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
92 lines
5.9 KiB
JavaScript
92 lines
5.9 KiB
JavaScript
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/);
|
|
});
|