Öffnungszeiten: Speichern zeichnet nur neu, was sich geändert hat
Ungespeicherte Eingaben in anderen Formularen bleiben stehen: nach dem Speichern wird nur die Plankarte, die Planliste (mit den Eingaben der übrigen Karten), Feiertage oder Ausnahmen neu gezeichnet, „Nein, danke“ entfernt nur die Frage. Während des Speicherns sind auch die Eingabefelder gesperrt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
04a3525f79
commit
f01ed15247
6 files changed
+409
-58
No files matched your search
@@ -626,6 +626,220 @@ test('Ausnahmen: bei 100 Einträgen sind beide Knöpfe gesperrt', mitDom({}, asy
|
||||
assert.match(fx.text(abschnitt(fx, root, 'ausnahmen')), /Mehr als 100 Ausnahmen sind nicht möglich/)
|
||||
}))
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------- Nur neu zeichnen, was sich geändert hat
|
||||
const kurzerUrlaub = (id, text = '') => ({ id, art: 'urlaub', von: tagPlus(HEUTE, 10), bis: tagPlus(HEUTE, 10), text, modus: 'zu', fenster: [], plan: null })
|
||||
/** Einen eintägigen Betriebsurlaub über das Formular eintragen (ohne Frage nach der Hinweis-Leiste); die Antwort kommt als nächste aus der Warteschlange. */
|
||||
async function urlaubEintragen(fx, root, antwortDaten, version) {
|
||||
await fx.klick(fx.finde(root, '[data-werkzeug="urlaub-neu"]'))
|
||||
const form = urlaubsformular(fx, root)
|
||||
await fx.setze(feldIn(fx, form, 'von'), tagPlus(HEUTE, 10))
|
||||
await fx.setze(feldIn(fx, form, 'bis'), tagPlus(HEUTE, 10))
|
||||
fx.antworten.push(antwort(antwortDaten, version))
|
||||
await fx.klick(fx.finde(form, 'button[type="submit"]'))
|
||||
}
|
||||
|
||||
test('Plan speichern zeichnet nur diese Karte: ungespeicherte Eingaben in einem anderen Plan und in anderen Abschnitten bleiben stehen', mitDom({}, async (fx) => {
|
||||
const zwei = daten({ plaene: [plan(P1), plan(P2)] })
|
||||
const { root } = await oeffne(fx, { start: stand(zwei) })
|
||||
const karteA = planKarte(fx, root, P1)
|
||||
const karteB = planKarte(fx, root, P2)
|
||||
const nameB = fx.finde(karteB, `[data-feld="plaene.${P2}.name"]`)
|
||||
await fx.setze(nameB, 'Küche Entwurf')
|
||||
await fx.klick(haken(fx, tagZeile(fx, root, P2, '7'))) // Sonntag im zweiten Plan geöffnet, nicht gespeichert
|
||||
await fx.setze(fx.finde(root, 'select[data-feld="land"]'), 'BY') // Bundesland gewählt, nicht gespeichert
|
||||
await fx.setze(fx.finde(fx.finde(root, '[data-feiertag="2026-12-25"]'), 'select'), 'rund')
|
||||
await fx.setze(zeitFelder(fx, tagZeile(fx, root, P1, '2'))[0], '08:15') // Dienstag in A: wird gleich gespeichert
|
||||
fx.antworten.push(antwort(daten({ plaene: [plan(P1, { tage: { ...werktags(), 2: { modus: 'zeiten', fenster: [['08:15', '18:00']] } } }), plan(P2)] }), 4))
|
||||
await fx.klick(speichernKnopf(fx, root, P1))
|
||||
const gesendet = puts(fx)[0].body.daten
|
||||
assert.deepEqual(gesendet.plaene[0].tage['2'].fenster, [['08:15', '18:00']])
|
||||
assert.equal(gesendet.plaene[1].name, 'Küche', 'der Entwurf des anderen Plans wird nicht mitgespeichert')
|
||||
assert.equal(gesendet.plaene[1].tage['7'].modus, 'zu')
|
||||
assert.notEqual(planKarte(fx, root, P1), karteA, 'die gespeicherte Karte ist neu gezeichnet')
|
||||
assert.equal(planKarte(fx, root, P2), karteB, 'die andere Karte ist dieselbe geblieben')
|
||||
assert.equal(fx.finde(planKarte(fx, root, P2), `[data-feld="plaene.${P2}.name"]`), nameB)
|
||||
assert.equal(nameB.value, 'Küche Entwurf')
|
||||
assert.equal(haken(fx, tagZeile(fx, root, P2, '7')).checked, true)
|
||||
assert.equal(fx.finde(root, 'select[data-feld="land"]').value, 'BY', 'das ungespeicherte Bundesland bleibt')
|
||||
assert.equal(fx.finde(fx.finde(root, '[data-feiertag="2026-12-25"]'), 'select').value, 'rund')
|
||||
assert.deepEqual(zeitFelder(fx, tagZeile(fx, root, P1, '2')).slice(0, 2).map((f) => f.value), ['08:15', '18:00'], 'die gespeicherte Karte zeigt den gespeicherten Stand')
|
||||
}))
|
||||
|
||||
test('Betriebsurlaub speichern zeichnet nur „Ausnahmen“: eine ungespeicherte Änderung am Wochenplan bleibt', mitDom({}, async (fx) => {
|
||||
const { root } = await oeffne(fx)
|
||||
const montag = tagZeile(fx, root, P1, '1')
|
||||
const feld = zeitFelder(fx, montag)[0]
|
||||
await fx.setze(feld, '07:45')
|
||||
const karte = planKarte(fx, root, P1)
|
||||
const feiertage = abschnitt(fx, root, 'feiertage')
|
||||
const ausnahmenVorher = abschnitt(fx, root, 'ausnahmen')
|
||||
await urlaubEintragen(fx, root, daten({ ausnahmen: [kurzerUrlaub('x_urlaub01')] }), 4)
|
||||
assert.equal(planKarte(fx, root, P1), karte, 'dieselbe Karte')
|
||||
assert.equal(zeitFelder(fx, tagZeile(fx, root, P1, '1'))[0], feld)
|
||||
assert.equal(feld.value, '07:45', 'die ungespeicherte Eingabe steht noch da')
|
||||
assert.equal(abschnitt(fx, root, 'feiertage'), feiertage, 'Feiertage unberührt')
|
||||
assert.notEqual(abschnitt(fx, root, 'ausnahmen'), ausnahmenVorher, 'Ausnahmen neu gezeichnet')
|
||||
assert.ok(fx.finde(root, 'li[data-id="x_urlaub01"]'))
|
||||
assert.match(meldung(fx, root), /eingetragen/)
|
||||
assert.equal(puts(fx)[0].body.daten.plaene[0].tage['1'].fenster[0][0], '09:00', 'der Entwurf ging nicht mit hinaus')
|
||||
// dasselbe beim Entfernen
|
||||
const zeile = fx.finde(root, 'li[data-id="x_urlaub01"]')
|
||||
await fx.klick(fx.finde(zeile, '[data-aktion="bearbeiten"]'))
|
||||
await fx.klick(fx.finde(zeile, '[data-aktion="entfernen"]'))
|
||||
fx.antworten.push(antwort(daten(), 5))
|
||||
await fx.klick(fx.finde(fx.finde(zeile, '.tm-frage-box'), 'button[type="submit"]'))
|
||||
assert.equal(feld.value, '07:45')
|
||||
assert.equal(fx.finde(root, 'li[data-id="x_urlaub01"]'), null)
|
||||
}))
|
||||
|
||||
test('„Nein, danke“ entfernt nur die Frage: andere ungespeicherte Eingaben und offene Formulare bleiben', mitDom({}, async (fx) => {
|
||||
const { root } = await oeffne(fx)
|
||||
await fx.klick(fx.finde(root, '[data-werkzeug="urlaub-neu"]'))
|
||||
const form = urlaubsformular(fx, root)
|
||||
const von = tagPlus(HEUTE, 20)
|
||||
const bis = tagPlus(HEUTE, 25)
|
||||
await fx.setze(feldIn(fx, form, 'von'), von)
|
||||
await fx.setze(feldIn(fx, form, 'bis'), bis)
|
||||
fx.antworten.push(antwort(daten({ ausnahmen: [{ ...kurzerUrlaub('x_urlaub01'), von, bis }] }), 4))
|
||||
await fx.klick(fx.finde(form, 'button[type="submit"]'))
|
||||
assert.ok(fx.finde(root, '[data-frage="hinweis"]'))
|
||||
// jetzt nebenher etwas eingeben: ein Wochentag, ein offenes Sondertag-Formular mit Text
|
||||
const feld = zeitFelder(fx, tagZeile(fx, root, P1, '3'))[1]
|
||||
await fx.setze(feld, '17:20')
|
||||
await fx.klick(fx.finde(root, '[data-werkzeug="sondertag-neu"]'))
|
||||
const sonder = fx.finde(root, 'form[aria-label="Sondertag eintragen"]')
|
||||
await fx.setze(feldIn(fx, sonder, 'text'), 'Tag der offenen Tür')
|
||||
await fx.klick(fx.finde(fx.finde(root, '[data-frage="hinweis"]'), '[data-aktion="hinweis-nein"]'))
|
||||
assert.equal(fx.finde(root, '[data-frage="hinweis"]'), null, 'die Frage ist weg')
|
||||
assert.equal(feld.value, '17:20')
|
||||
assert.equal(fx.finde(root, 'form[aria-label="Sondertag eintragen"]'), sonder, 'das offene Formular ist dasselbe')
|
||||
assert.equal(feldIn(fx, sonder, 'text').value, 'Tag der offenen Tür')
|
||||
assert.equal(puts(fx).length, 1)
|
||||
}))
|
||||
|
||||
test('Feiertage speichern lässt ein noch ungespeichertes Bundesland stehen; Bundesland speichern nimmt Eingaben für Tage mit ins neue Land', mitDom({}, async (fx) => {
|
||||
const { root } = await oeffne(fx)
|
||||
const zeile = (tag) => fx.finde(root, `[data-feiertag="${tag}"]`)
|
||||
await fx.setze(fx.finde(root, 'select[data-feld="land"]'), 'BY')
|
||||
await fx.setze(fx.finde(zeile('2026-12-25'), 'select'), 'vereinbarung')
|
||||
fx.antworten.push(antwort(daten({ feiertage: { '2026-12-25': { modus: 'vereinbarung', fenster: [] } } }), 4))
|
||||
await fx.klick(fx.finde(root, 'form[aria-label="Feiertage"] button[type="submit"]'))
|
||||
assert.equal(puts(fx)[0].body.daten.land, 'RP', 'das Bundesland ging nicht mit')
|
||||
assert.equal(fx.finde(root, 'select[data-feld="land"]').value, 'BY', 'und steht noch da')
|
||||
assert.match(meldung(fx, root), /Feiertage gespeichert/)
|
||||
|
||||
// jetzt das Bundesland speichern: ein Wochenplan-Entwurf bleibt, die Eingabe zu Neujahr (gibt es auch in Bayern) wandert mit
|
||||
await fx.setze(fx.finde(zeile('2027-01-01'), 'select'), 'rund')
|
||||
const feld = zeitFelder(fx, tagZeile(fx, root, P1, '4'))[0]
|
||||
await fx.setze(feld, '10:10')
|
||||
const bayern = [{ tag: '2026-12-25', name: 'Erster Weihnachtstag', art: 'feiertag' }, { tag: '2027-01-01', name: 'Neujahr', art: 'feiertag' }, { tag: '2027-01-06', name: 'Heilige Drei Könige', art: 'feiertag' }]
|
||||
fx.antworten.push(antwort(daten({ land: 'BY', feiertage: { '2026-12-25': { modus: 'vereinbarung', fenster: [] } } }), 5, { feiertage: bayern }))
|
||||
await fx.klick(fx.finde(root, 'form[aria-label="Bundesland"] button[type="submit"]'))
|
||||
assert.deepEqual(fx.alle(root, '[data-feiertag]').map((z) => z.getAttribute('data-feiertag')), ['2026-12-25', '2027-01-01', '2027-01-06'])
|
||||
assert.equal(fx.finde(zeile('2027-01-01'), 'select').value, 'rund', 'die Eingabe zu Neujahr ist erhalten')
|
||||
assert.equal(fx.finde(zeile('2026-12-25'), 'select').value, 'vereinbarung', 'der gespeicherte Stand')
|
||||
assert.equal(fx.finde(zeile('2027-01-06'), 'select').value, '')
|
||||
assert.equal(feld.value, '10:10', 'der Wochenplan-Entwurf bleibt')
|
||||
}))
|
||||
|
||||
test('Plan hinzufügen, Hauptplan wechseln und Plan löschen zeichnen die Planliste neu, behalten aber die ungespeicherten Eingaben der übrigen Karten und das offene „Plan hinzufügen“', mitDom({}, async (fx) => {
|
||||
const P3 = 'p_dritter3'
|
||||
const d3 = daten({
|
||||
plaene: [plan(P1), plan(P2), plan(P3, { kurz: 'bar', name: 'Bar', haupt: false })],
|
||||
ausnahmen: [{ ...kurzerUrlaub('x_kueche01', 'Nur Küche'), plan: P2 }, kurzerUrlaub('x_alle0001', 'Alle')],
|
||||
})
|
||||
const { root } = await oeffne(fx, { start: stand(d3) })
|
||||
const name3 = fx.finde(planKarte(fx, root, P3), `[data-feld="plaene.${P3}.name"]`)
|
||||
await fx.setze(name3, 'Bar Entwurf')
|
||||
const montag = zeitFelder(fx, tagZeile(fx, root, P1, '1'))[0]
|
||||
await fx.setze(montag, '06:30')
|
||||
await fx.klick(fx.finde(root, '[data-werkzeug="plan-neu"]'))
|
||||
const neuForm = fx.finde(root, 'form[aria-label="Plan hinzufügen"]')
|
||||
await fx.setze(fx.finde(neuForm, 'input[type="text"]'), 'Halbfertig')
|
||||
const ausnahmenVorher = abschnitt(fx, root, 'ausnahmen')
|
||||
|
||||
// Hauptplan wechseln (P2): Pillen und Knöpfe aller Karten ändern sich, die Eingaben bleiben
|
||||
fx.antworten.push(antwort(daten({ ...d3, plaene: [plan(P1, { haupt: false }), plan(P2, { haupt: true }), plan(P3, { kurz: 'bar', name: 'Bar', haupt: false })] }), 4))
|
||||
await fx.klick(fx.finde(planKarte(fx, root, P2), '[data-aktion="haupt"]'))
|
||||
assert.match(fx.text(fx.finde(planKarte(fx, root, P2), 'summary')), /Hauptplan/)
|
||||
assert.doesNotMatch(fx.text(fx.finde(planKarte(fx, root, P1), 'summary')), /Hauptplan/)
|
||||
assert.ok(fx.finde(planKarte(fx, root, P1), '[data-aktion="haupt"]'), 'der frühere Hauptplan hat jetzt den Knopf')
|
||||
assert.equal(fx.finde(planKarte(fx, root, P3), `[data-feld="plaene.${P3}.name"]`).value, 'Bar Entwurf')
|
||||
assert.equal(zeitFelder(fx, tagZeile(fx, root, P1, '1'))[0].value, '06:30')
|
||||
assert.equal(fx.finde(root, 'form[aria-label="Plan hinzufügen"]'), neuForm, 'das offene Formular bleibt')
|
||||
assert.equal(fx.finde(neuForm, 'input[type="text"]').value, 'Halbfertig')
|
||||
assert.equal(abschnitt(fx, root, 'ausnahmen'), ausnahmenVorher, 'die Ausnahmen kennen die Pläne nur beim Namen: nichts zu tun')
|
||||
|
||||
// Plan löschen (P3, jetzt weder Haupt- noch letzter Plan): P1 und P2 behalten ihre Eingaben, Ausnahmen werden neu gezeichnet
|
||||
const montag2 = zeitFelder(fx, tagZeile(fx, root, P1, '1'))[0]
|
||||
await fx.klick(fx.finde(planKarte(fx, root, P3), '[data-aktion="entfernen"]'))
|
||||
fx.antworten.push(antwort(daten({ ...d3, plaene: [plan(P1, { haupt: false }), plan(P2, { haupt: true })] }), 5))
|
||||
await fx.klick(fx.finde(fx.finde(planKarte(fx, root, P3), '.tm-frage-box'), 'button[type="submit"]'))
|
||||
assert.equal(planKarte(fx, root, P3), null)
|
||||
assert.equal(zeitFelder(fx, tagZeile(fx, root, P1, '1'))[0].value, '06:30', 'Eingabe in P1 bleibt')
|
||||
assert.notEqual(zeitFelder(fx, tagZeile(fx, root, P1, '1'))[0], montag2, '(die Karte wurde mit ihren Werten neu gebaut)')
|
||||
assert.equal(fx.finde(root, 'form[aria-label="Plan hinzufügen"]'), neuForm)
|
||||
assert.notEqual(abschnitt(fx, root, 'ausnahmen'), ausnahmenVorher, 'Ausnahmen neu gezeichnet')
|
||||
|
||||
// Plan hinzufügen: neue Karte, Formular zu, P1 behält die Eingabe, „Gilt für“ in neuen Formularen kennt den neuen Plan
|
||||
await fx.setze(fx.finde(neuForm, 'input[type="text"]'), 'Lieferdienst')
|
||||
fx.antworten.push((aufruf) => antwort(daten({ ...d3, plaene: [plan(P1, { haupt: false }), plan(P2, { haupt: true }), plan(aufruf.body.daten.plaene[2].id, { kurz: 'lieferdienst', name: 'Lieferdienst', haupt: false, tage: wochenplan() })] }), 6))
|
||||
await fx.klick(fx.finde(neuForm, 'button[type="submit"]'))
|
||||
const neueKarte = fx.alle(root, 'details[data-plan]').find((k) => /Lieferdienst/.test(fx.text(fx.finde(k, 'summary'))))
|
||||
assert.ok(neueKarte, 'die neue Karte steht in der Liste')
|
||||
assert.equal(fx.alle(root, 'details[data-plan]').length, 3)
|
||||
assert.equal(fx.finde(root, 'form[aria-label="Plan hinzufügen"]'), null, 'das Formular ist zu')
|
||||
assert.equal(zeitFelder(fx, tagZeile(fx, root, P1, '1'))[0].value, '06:30', 'auch das Hinzufügen lässt die Eingaben der anderen Karten stehen')
|
||||
await fx.klick(fx.finde(root, '[data-werkzeug="urlaub-neu"]'))
|
||||
assert.match(fx.text(feldIn(fx, urlaubsformular(fx, root), 'plan')), /Lieferdienst/)
|
||||
}))
|
||||
|
||||
test('Plan umbenennen: die Liste der Ausnahmen nennt den neuen Namen, sonst bleibt sie stehen', mitDom({}, async (fx) => {
|
||||
const ausnahme = { ...kurzerUrlaub('x_kueche01', 'Nur Küche'), plan: P2 }
|
||||
const { root } = await oeffne(fx, { start: stand(daten({ plaene: [plan(P1), plan(P2)], ausnahmen: [ausnahme] })) })
|
||||
const vorher = abschnitt(fx, root, 'ausnahmen')
|
||||
assert.match(fx.text(fx.finde(root, 'li[data-id="x_kueche01"]')), /nur Küche/)
|
||||
// erst gespeichert ohne neuen Namen: Ausnahmen bleiben
|
||||
fx.antworten.push(antwort(daten({ plaene: [plan(P1), plan(P2)], ausnahmen: [ausnahme] }), 4))
|
||||
await fx.klick(speichernKnopf(fx, root, P2))
|
||||
assert.equal(abschnitt(fx, root, 'ausnahmen'), vorher)
|
||||
await fx.setze(fx.finde(planKarte(fx, root, P2), `[data-feld="plaene.${P2}.name"]`), 'Restaurant')
|
||||
fx.antworten.push(antwort(daten({ plaene: [plan(P1), plan(P2, { name: 'Restaurant' })], ausnahmen: [ausnahme] }), 5))
|
||||
await fx.klick(speichernKnopf(fx, root, P2))
|
||||
assert.notEqual(abschnitt(fx, root, 'ausnahmen'), vorher)
|
||||
assert.match(fx.text(fx.finde(root, 'li[data-id="x_kueche01"]')), /nur Restaurant/)
|
||||
}))
|
||||
|
||||
test('Während ein Speichern läuft, sind Knöpfe und Eingabefelder gesperrt (nichts geht beim Tippen verloren); danach sind sie wieder frei', mitDom({}, async (fx) => {
|
||||
const { root } = await oeffne(fx, { start: stand(daten({ plaene: [plan(P1), plan(P2)] })) })
|
||||
const echtes = globalThis.fetch
|
||||
let freigeben
|
||||
const wartet = new Promise((resolve) => { freigeben = resolve })
|
||||
globalThis.fetch = async (url, optionen) => {
|
||||
if (optionen?.method === 'PUT') await wartet
|
||||
return echtes(url, optionen)
|
||||
}
|
||||
try {
|
||||
const ausserhalb = zeitFelder(fx, tagZeile(fx, root, P2, '1'))[0]
|
||||
const selbst = zeitFelder(fx, tagZeile(fx, root, P1, '1'))[0]
|
||||
fx.antworten.push(antwort(daten({ plaene: [plan(P1), plan(P2)] }), 4))
|
||||
const lauf = fx.klick(speichernKnopf(fx, root, P1))
|
||||
await fx.ruhe()
|
||||
assert.equal(root.getAttribute('aria-busy'), 'true')
|
||||
for (const steuerung of fx.alle(root, 'input, select, textarea, button')) assert.equal(steuerung.disabled, true, `${steuerung.tagName} ist gesperrt`)
|
||||
await fx.setze(ausserhalb, '05:55')
|
||||
assert.notEqual(ausserhalb.value, '05:55', 'in ein gesperrtes Feld lässt sich nichts tippen')
|
||||
freigeben()
|
||||
await lauf
|
||||
assert.equal(root.hasAttribute('aria-busy'), false)
|
||||
assert.equal(ausserhalb.disabled, false, 'die Karte, die stehen blieb, ist wieder frei')
|
||||
assert.equal(fx.alle(root, 'input:disabled, select:disabled, button:disabled').length, 0)
|
||||
void selbst
|
||||
} finally {
|
||||
globalThis.fetch = echtes
|
||||
}
|
||||
}))
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------- Fehler des Servers
|
||||
test('409 beim Speichern: Meldung „Inzwischen geändert – bitte neu laden.“ und Neu-laden-Knopf; der Knopf lädt und zeichnet neu', mitDom({}, async (fx) => {
|
||||
const { root } = await oeffne(fx)
|
||||
|
||||
Reference in new issue
Block a user