import { test } from 'node:test' import assert from 'node:assert/strict' import { installFakeDom } from './support/fakeDom.js' import { h, request } from '../public/shop-dom.js' import { REITER } from '../public/buchungen.js' import { render, zeitraumText, naechteText } from '../public/buchungen-tab-anfragen.js' import { summeLive } from '../public/buchungen-posten.js' // Task 12: Gerüst und Reiter „Anfragen“ gegen eine Anfrage-Attrappe nach docs/funktionen/unterkunft-api.md. const POSTEN = [ { text: 'Übernachtung', menge: 7, einzelCent: 5500, ustProzent: 7 }, { text: 'Reinigung', menge: 1, einzelCent: 6000, ustProzent: 7 }, { text: 'Direktbuchungsrabatt 10 %', menge: 1, einzelCent: -3850, ustProzent: 7 }, ] const zeile = (nr, extra = {}) => ({ id: `a${nr}`, nummer: `A-${nr}`, von: '2026-11-12', bis: '2026-11-30', gast: { name: `Gast ${nr}` }, status: 'neu', summen: { bruttoCent: 40650 }, ...extra }) const anfrage = (extra = {}) => ({ id: 'a1', nummer: 'A-1', von: '2026-11-12', bis: '2026-11-19', personen: 2, status: 'neu', steuerart: 'regelbesteuert', unterkunftName: 'Haus am See', gast: { name: 'Anna Muster', email: 'anna@example.com', telefon: '0151', nachricht: 'Hund dabei' }, ...extra, }) const vorschlag = { naechte: 7, posten: POSTEN, summen: { bruttoCent: 40650 } } const mit = (route, fn) => async () => { const fx = installFakeDom({ antworten: Array.from({ length: 40 }, () => route) }) try { await fn(fx) } finally { fx.restore() } } function baueCtx() { const ctx = { projectId: 'p1', status: { state: 'active' }, nurLesen: false, meldungen: [], aktuell: () => true, request, zeigeMeldung: (t, a) => ctx.meldungen.push({ text: t, art: a }), neuLaden: async () => ctx.status } return ctx } async function zeige(fx) { const ctx = baueCtx() const panel = h('div') fx.document.body.append(panel) await render(panel, ctx) await fx.ruhe() return { panel, ctx } } const server = (o = {}) => (a) => { const key = `${a.method} ${a.url.split('?')[0]}` if (o[key]) return o[key](a) if (a.method === 'GET' && a.url.startsWith('/api/unterkunft/anfragen?')) return { body: { anfragen: [zeile(1), zeile(2, { status: 'gebucht' })] } } if (a.method === 'GET' && a.url.startsWith('/api/unterkunft/anfragen/')) return { body: { anfrage: anfrage(), vorschlag } } return { body: {} } } const posts = (fx) => fx.fetchLog.filter((a) => a.method !== 'GET') const aktion = (fx, el, n) => fx.finde(el, `[data-aktion="${n}"]`) const oeffne = async (fx, panel, id = 'a1') => { await fx.klick(fx.finde(panel, `[data-anfrage="${id}"]`)); await fx.ruhe() } test('REITER: fünf Reiter mit den Labels', () => { assert.deepEqual(REITER.map((r) => r.key), ['anfragen', 'kalender', 'unterkuenfte', 'rechnungen', 'einstellungen']) assert.deepEqual(REITER.map((r) => r.label), ['Anfragen', 'Kalender', 'Unterkünfte & Preise', 'Rechnungen', 'Einstellungen']) }) test('summeLive spiegelt summiere: 40650 / 37991 / 2659', () => { const s = summeLive(POSTEN, 'regelbesteuert') assert.equal(s.bruttoCent, 40650) assert.equal(s.nettoCent, 37991) assert.equal(s.ust[0].steuerCent, 2659) const k = summeLive(POSTEN, 'kleinunternehmer') assert.deepEqual(k, { bruttoCent: 40650, nettoCent: 40650, ust: [] }) }) test('Zeitraum und Nächte', () => { assert.equal(zeitraumText('2026-11-12', '2026-11-30'), '12.–30.11.2026') assert.equal(zeitraumText('2026-10-28', '2026-11-03'), '28.10.–03.11.2026') assert.equal(zeitraumText('2026-12-28', '2027-01-03'), '28.12.2026–03.01.2027') assert.equal(naechteText('2026-11-12', '2026-11-30'), '18 Nächte') assert.equal(naechteText('2026-11-12', '2026-11-13'), '1 Nacht') }) test('Liste: Nummer, Zeitraum, Gast, Status-Pille, Betrag; Filter offen als Standard', mit(server(), async (fx) => { const { panel } = await zeige(fx) assert.equal(fx.fetchLog[0].url, '/api/unterkunft/anfragen?projectId=p1&filter=offen') const z = fx.alle(panel, '[data-anfrage]') assert.equal(z.length, 2) const t = fx.text(z[0]) for (const re of [/A-1/, /12\.–30\.11\.2026 · 18 Nächte/, /Gast 1/, /Neu/, /406,50\s€/]) assert.match(t, re) assert.match(fx.text(z[1]), /Gebucht/) await fx.setze(fx.finde(panel, '#bk-a-filter'), 'alle') await fx.ruhe() assert.equal(fx.fetchLog.at(-1).url, '/api/unterkunft/anfragen?projectId=p1&filter=alle') })) test('Detail: Vorschlag editierbar, Summe aktualisiert sich, Freigeben sendet posten/fristTage/nachricht und zeigt den Link', mit(server({ 'POST /api/unterkunft/anfragen/a1/freigeben': () => ({ body: { buchungsLink: 'https://x.test/buchen/a1?t=abc' } }), }), async (fx) => { const { panel, ctx } = await zeige(fx) await oeffne(fx, panel) assert.match(fx.text(panel), /Anna Muster<\/b>/) assert.equal(fx.finde(panel, 'b'), null, 'Fremdtext bleibt Text') assert.match(fx.text(fx.finde(panel, '[data-summen]')), /Gesamt 406,50\s€/) const zeilen = fx.alle(panel, '[data-zeile]') assert.equal(zeilen.length, 3) const einzel = fx.finde(zeilen[1], '[data-posten="einzel"]') await fx.setze(einzel, '70,00') assert.match(fx.text(fx.finde(panel, '[data-summen]')), /Gesamt 416,50\s€/) await fx.setze(einzel, '60,00') await fx.setze(fx.finde(panel, '#bk-a-frist'), '5') await fx.setze(fx.finde(panel, '#bk-a-nachricht'), 'Gern!') await fx.klick(aktion(fx, panel, 'freigeben')) await fx.ruhe() const [p] = posts(fx) assert.equal(p.url, '/api/unterkunft/anfragen/a1/freigeben?projectId=p1') assert.deepEqual(p.body, { posten: POSTEN, fristTage: 5, nachricht: 'Gern!' }) assert.equal(fx.finde(panel, '[data-link]').getAttribute('value'), 'https://x.test/buchen/a1?t=abc') assert.ok(aktion(fx, panel, 'link-kopieren')) assert.equal(ctx.meldungen.at(-1).art, 'ok') })) test('Freigeben: 409 zeigt „Der Zeitraum ist inzwischen belegt.“', mit(server({ 'POST /api/unterkunft/anfragen/a1/freigeben': () => ({ status: 409, body: { fehler: 'zeitraum_belegt' } }), }), async (fx) => { const { panel } = await zeige(fx) await oeffne(fx, panel) await fx.klick(aktion(fx, panel, 'freigeben')) await fx.ruhe() assert.match(fx.text(panel), /Der Zeitraum ist inzwischen belegt\./) assert.equal(aktion(fx, panel, 'freigeben').disabled, false) })) test('Ablehnen sendet den Text', mit(server({ 'POST /api/unterkunft/anfragen/a1/ablehnen': () => ({ body: {} }) }), async (fx) => { const { panel } = await zeige(fx) await oeffne(fx, panel) await fx.klick(aktion(fx, panel, 'ablehnen')) await fx.setze(fx.finde(panel, '#bk-a-ablehn'), 'Leider belegt') await fx.klick(aktion(fx, panel, 'ablehnen-senden')) await fx.ruhe() assert.deepEqual(posts(fx)[0].body, { text: 'Leider belegt' }) })) const gebucht = (extra = {}) => ({ anfrage: anfrage({ status: 'gebucht', posten: POSTEN, summen: { bruttoCent: 40650 }, rechnungId: 'r1', rechnungNummer: 'R-2026-001', ...extra }) }) test('Gebucht: Rechnung-Link, „Als bezahlt (vor Ort)“, Storno ohne Erstattungsfeld bei Vor-Ort-Zahlung', mit(server({ 'GET /api/unterkunft/anfragen/a1': () => ({ body: gebucht({ zahlart: 'vorort' }) }), 'POST /api/unterkunft/anfragen/a1/bezahlt': () => ({ body: {} }), 'POST /api/unterkunft/anfragen/a1/stornieren': () => ({ body: {} }), }), async (fx) => { const { panel } = await zeige(fx) await oeffne(fx, panel) assert.equal(aktion(fx, panel, 'rechnung').getAttribute('href'), '/api/unterkunft/rechnungen/r1.pdf?projectId=p1') await fx.klick(aktion(fx, panel, 'bezahlt')) await fx.ruhe() assert.equal(posts(fx)[0].url, '/api/unterkunft/anfragen/a1/bezahlt?projectId=p1') await fx.klick(aktion(fx, panel, 'stornieren')) assert.equal(fx.finde(panel, '#bk-a-erstattung'), null) await fx.setze(fx.finde(panel, '#bk-a-grund'), 'Gast krank') await fx.klick(aktion(fx, panel, 'storno-senden')) await fx.ruhe() assert.deepEqual(posts(fx).at(-1).body, { grund: 'Gast krank', erstattungCent: 0 }) })) test('Storno bei Online-Zahlung: Erstattungsbetrag wird gesendet', mit(server({ 'GET /api/unterkunft/anfragen/a1': () => ({ body: gebucht({ status: 'bezahlt', zahlart: 'online', bezahltVia: 'online' }) }), 'POST /api/unterkunft/anfragen/a1/stornieren': () => ({ body: {} }), }), async (fx) => { const { panel } = await zeige(fx) await oeffne(fx, panel) assert.equal(aktion(fx, panel, 'bezahlt'), null) await fx.klick(aktion(fx, panel, 'stornieren')) assert.equal(fx.finde(panel, '#bk-a-erstattung').value, '406,50') await fx.setze(fx.finde(panel, '#bk-a-erstattung'), '200,00') await fx.klick(aktion(fx, panel, 'storno-senden')) await fx.ruhe() assert.equal(posts(fx)[0].body.erstattungCent, 20000) })) // Task 13: Reiter „Kalender“ und „Unterkünfte & Preise“ (Antwortformen: ui-erwartungen.md) const UK = { id: 'u1', name: 'Haus am See', beschreibung: 'Schön', maxPersonen: 4, mindestNaechte: 2, checkIn: '15:00', checkOut: '10:00', sort: 0, aktiv: true, icalExportUrl: 'https://x.test/unterkunft/ical/tok.ics', icalImporte: [{ id: 'i1', name: 'Booking.com', url: 'https://b.test/x.ics', letzterErfolgAt: '2026-10-07T10:00:00.000Z', fehler: '' }, { id: 'i2', name: 'Airbnb', url: 'https://a.test/x.ics', fehler: 'Zeitüberschreitung' }] } const PREISE = { staffeln: [{ abNaechten: 1, preisProNachtCent: 5500 }, { abNaechten: 7, preisProNachtCent: 5000 }], reinigungCent: 6000, personenInklusive: 2, aufpreisPersonNachtCent: 1000, direktrabattProzent: 10, steuerart: 'regel', ustUebernachtung: 7, ustReinigung: 7, fristTage: 3, stornobedingungen: 'Kostenlos bis 14 Tage vorher.' } const BEREICHE = [ { von: '2026-11-03', bis: '2026-11-06', quelle: 'gebucht', anfrageNummer: 'A-1' }, { von: '2026-11-10', bis: '2026-11-12', quelle: 'reserviert' }, { von: '2026-11-15', bis: '2026-11-17', quelle: 'ical:i1' }, { von: '2026-11-20', bis: '2026-11-22', quelle: 'manuell', sperreId: 's1', notiz: 'Eigenbedarf' }, ] const ukServer = (o = {}) => (a) => { const key = `${a.method} ${a.url.split('?')[0]}` if (o[key]) return o[key](a) if (key === 'GET /api/unterkunft/unterkuenfte') return { body: { unterkuenfte: [UK] } } if (key === 'GET /api/unterkunft/unterkuenfte/u1/kalender') return { body: { bereiche: BEREICHE } } if (key === 'GET /api/unterkunft/unterkuenfte/u1/preise') return { body: { preise: PREISE } } if (key === 'POST /api/unterkunft/preisvorschau') return { body: { naechte: 7, posten: [], summen: { bruttoCent: 40650 } } } return { body: {} } } const zeigeTab = async (fx, modul) => { const ctx = baueCtx() const panel = h('div') fx.document.body.append(panel) await modul.render(panel, ctx) await fx.ruhe() return { panel, ctx } } const kal = await import('../public/buchungen-tab-kalender.js') const ukTab = await import('../public/buchungen-tab-unterkuenfte.js') const tag = (fx, panel, t) => fx.finde(panel, `[data-tag="${t}"]`) const gehZuNovember = async (fx, panel) => { while (!/November 2026/.test(fx.text(fx.finde(panel, '[data-monat]')))) { await fx.klick(aktion(fx, panel, 'weiter')); await fx.ruhe() } } test('rasterTage: November 2026 beginnt am Montag 26.10. und endet am Sonntag 29.11.... ', () => { const t = kal.rasterTage(2026, 10) assert.equal(t[0], '2026-10-26') assert.equal(t.length % 7, 0) assert.equal(t.at(-1), '2026-12-06') assert.equal(kal.rasterTage(2026, 5)[0], '2026-06-01') // Juni 2026 beginnt am Montag }) test('Kalender: Raster Montag zuerst, Farben nach Quelle, Legende', mit(ukServer(), async (fx) => { const { panel } = await zeigeTab(fx, kal) await gehZuNovember(fx, panel) assert.equal(fx.text(fx.alle(panel, '[role="columnheader"]')[0]), 'Mo') assert.equal(fx.alle(panel, '[data-tag]')[0].dataset.tag, '2026-10-26') assert.ok(tag(fx, panel, '2026-11-03').classList.contains('ist-gebucht')) assert.ok(!tag(fx, panel, '2026-11-06').classList.contains('ist-gebucht'), 'Abreisetag ist frei') assert.ok(tag(fx, panel, '2026-11-10').classList.contains('ist-reserviert')) assert.ok(tag(fx, panel, '2026-11-16').classList.contains('ist-ical')) assert.ok(tag(fx, panel, '2026-11-20').classList.contains('ist-manuell')) assert.ok(tag(fx, panel, '2026-11-08').classList.contains('ist-frei')) for (const t of ['Direkt gebucht', 'Reserviert', 'Booking.com / Airbnb', 'Von dir gesperrt']) assert.match(fx.text(panel), new RegExp(t)) assert.ok(fx.fetchLog.some((a) => /kalender\?projectId=p1&von=2026-10-26&bis=2026-12-07$/.test(a.url))) })) test('Kalender: zwei Klicks auf freie Tage → Notiz → POST sperren', mit(ukServer({ 'POST /api/unterkunft/unterkuenfte/u1/sperren': () => ({ status: 201, body: {} }) }), async (fx) => { const { panel } = await zeigeTab(fx, kal) await gehZuNovember(fx, panel) await fx.klick(tag(fx, panel, '2026-11-25')) assert.equal(posts(fx).length, 0) await fx.klick(tag(fx, panel, '2026-11-27')) assert.match(fx.text(panel), /Zeitraum sperren/) await fx.setze(fx.finde(panel, '#bk-k-notiz'), 'Familie') await fx.klick(aktion(fx, panel, 'sperren-senden')) await fx.ruhe() const [p] = posts(fx) assert.equal(p.url, '/api/unterkunft/unterkuenfte/u1/sperren?projectId=p1') assert.deepEqual(p.body, { von: '2026-11-25', bis: '2026-11-28', notiz: 'Familie' }) })) test('Kalender: Zeitraum über belegte Tage wird nicht angeboten; 409 vom Server wird gezeigt', mit(ukServer({ 'POST /api/unterkunft/unterkuenfte/u1/sperren': () => ({ status: 409, body: { fehler: 'zeitraum_belegt' } }) }), async (fx) => { const { panel } = await zeigeTab(fx, kal) await gehZuNovember(fx, panel) await fx.klick(tag(fx, panel, '2026-11-08')) await fx.klick(tag(fx, panel, '2026-11-13')) assert.equal(aktion(fx, panel, 'sperren-senden'), null) assert.match(fx.text(fx.finde(panel, '[data-hinweis]')), /belegte Tage/) await fx.klick(tag(fx, panel, '2026-11-24')) await fx.klick(tag(fx, panel, '2026-11-24')) await fx.klick(aktion(fx, panel, 'sperren-senden')) await fx.ruhe() assert.match(fx.text(panel), /Der Zeitraum ist bereits belegt\./) })) test('Kalender: Klick auf manuelle Sperre bietet „Sperre aufheben“ (DELETE); andere Quellen nicht', mit(ukServer({ 'DELETE /api/unterkunft/sperren/s1': () => ({ body: {} }) }), async (fx) => { const { panel } = await zeigeTab(fx, kal) await gehZuNovember(fx, panel) await fx.klick(tag(fx, panel, '2026-11-04')) assert.equal(aktion(fx, panel, 'aufheben'), null) await fx.klick(tag(fx, panel, '2026-11-21')) assert.match(fx.text(panel), /Eigenbedarf/) await fx.klick(aktion(fx, panel, 'aufheben')) await fx.ruhe() const [p] = posts(fx) assert.equal(p.method, 'DELETE') assert.equal(p.url, '/api/unterkunft/sperren/s1?projectId=p1') })) test('Unterkünfte: Liste mit Fremdtext als Text; Formular hat alle Felder; Speichern sendet PUT', mit(ukServer({ 'PUT /api/unterkunft/unterkuenfte/u1': () => ({ body: { unterkunft: UK } }) }), async (fx) => { const { panel } = await zeigeTab(fx, ukTab) assert.match(fx.text(panel), /Haus am<\/i> See/) assert.equal(fx.finde(panel, 'i'), null) await fx.klick(aktion(fx, panel, 'bearbeiten')) await fx.ruhe() for (const f of ['name', 'beschreibung', 'maxPersonen', 'mindestNaechte', 'checkIn', 'checkOut', 'aktiv']) assert.ok(fx.finde(panel, `[data-feld="${f}"]`), f) await fx.setze(fx.finde(panel, '#bk-u-max'), '6') await fx.klick(fx.finde(panel, '.bk-unterkuenfte form [data-aktion="speichern"]')) await fx.ruhe() const put = posts(fx).find((a) => a.method === 'PUT') assert.equal(put.url, '/api/unterkunft/unterkuenfte/u1?projectId=p1') assert.deepEqual(put.body, { name: UK.name, beschreibung: 'Schön', maxPersonen: 6, mindestNaechte: 2, checkIn: '15:00', checkOut: '10:00', sort: 0, aktiv: true }) })) test('Unterkünfte: Feldfehler (400 mit felder) kommen am Feld an', mit(ukServer({ 'PUT /api/unterkunft/unterkuenfte/u1': () => ({ status: 400, body: { fehler: 'ungueltig', felder: { name: 'Name ist schon vergeben.' } } }) }), async (fx) => { const { panel } = await zeigeTab(fx, ukTab) await fx.klick(aktion(fx, panel, 'bearbeiten')) await fx.ruhe() await fx.klick(fx.finde(panel, '.bk-unterkuenfte form [data-aktion="speichern"]')) await fx.ruhe() assert.equal(fx.text(fx.finde(panel, '[data-fehler="name"]')), 'Name ist schon vergeben.') })) test('Unterkünfte: Neue Unterkunft prüft Felder lokal und sendet POST', mit(ukServer({ 'POST /api/unterkunft/unterkuenfte': () => ({ status: 201, body: { unterkunft: { ...UK, id: 'u2', name: 'Neu' } } }) }), async (fx) => { const { panel } = await zeigeTab(fx, ukTab) await fx.klick(aktion(fx, panel, 'neu')) await fx.klick(aktion(fx, panel, 'speichern')) assert.match(fx.text(fx.finde(panel, '[data-fehler="name"]')), /Namen/) assert.equal(posts(fx).length, 0) await fx.setze(fx.finde(panel, '#bk-u-name'), 'Neu') await fx.klick(aktion(fx, panel, 'speichern')) await fx.ruhe() const [p] = posts(fx) assert.equal(p.method, 'POST') assert.equal(p.body.name, 'Neu') assert.equal(p.body.sort, 1) })) test('Preis-Editor: Staffelzeilen +/−, Beispielrechnung über /preisvorschau, Speichern sendet Cent', mit(ukServer({ 'PUT /api/unterkunft/unterkuenfte/u1/preise': () => ({ body: {} }) }), async (fx) => { const { panel } = await zeigeTab(fx, ukTab) await fx.klick(aktion(fx, panel, 'bearbeiten')) await fx.ruhe() assert.match(fx.text(fx.finde(panel, '[data-vorschau]')), /7 Nächte, 2 Personen = 406,50\s€/) const vor = fx.fetchLog.find((a) => a.url.startsWith('/api/unterkunft/preisvorschau')) assert.equal(vor.method, 'POST') assert.equal(vor.body.unterkunftId, 'u1') assert.equal(vor.body.personen, 2) assert.equal(fx.alle(panel, '[data-staffel-zeile]').length, 2) await fx.klick(aktion(fx, panel, 'staffel-dazu')) assert.equal(fx.alle(panel, '[data-staffel-zeile]').length, 3) const neu = fx.alle(panel, '[data-staffel-zeile]')[2] await fx.setze(fx.finde(neu, '[data-staffel="ab"]'), '14') await fx.setze(fx.finde(neu, '[data-staffel="preis"]'), '45') await fx.klick(fx.finde(fx.alle(panel, '[data-staffel-zeile]')[1], '[data-aktion="staffel-weg"]')) assert.equal(fx.alle(panel, '[data-staffel-zeile]').length, 2) await fx.klick(aktion(fx, panel, 'preise-speichern')) await fx.ruhe() const put = posts(fx).find((a) => a.url.includes('/preise')) assert.equal(put.method, 'PUT') assert.deepEqual(put.body.staffeln, [{ abNaechten: 1, preisProNachtCent: 5500 }, { abNaechten: 14, preisProNachtCent: 4500 }]) assert.equal(put.body.reinigungCent, 6000) assert.equal(put.body.aufpreisPersonNachtCent, 1000) assert.equal(put.body.steuerart, 'regel') assert.equal(put.body.direktrabattProzent, 10) assert.equal(put.body.stornobedingungen, 'Kostenlos bis 14 Tage vorher.') })) test('iCal: Status je Import, Fehlertext, Export-Link, Anleitungen', mit(ukServer(), async (fx) => { const { panel } = await zeigeTab(fx, ukTab) await fx.klick(aktion(fx, panel, 'bearbeiten')) await fx.ruhe() assert.match(fx.text(fx.finde(panel, '[data-import="i1"]')), /Zuletzt abgeglichen 07\.10\.2026/) assert.match(fx.text(fx.finde(panel, '[data-import="i2"]')), /nicht geklappt: Zeitüberschreitung/) assert.equal(fx.finde(panel, '[data-export]').getAttribute('value'), UK.icalExportUrl) assert.ok(aktion(fx, panel, 'export-kopieren')) assert.match(fx.text(fx.finde(panel, '[data-anleitung="booking"]')), /Unterkunft → Tarife & Verfügbarkeit → Kalender synchronisieren → Kalender importieren → Link einfügen/) assert.ok(fx.finde(panel, '[data-anleitung="airbnb"]')) })) test('iCal: Import hinzufügen (POST), entfernen mit Rückfrage, Link erneuern mit Bestätigung', mit(ukServer({ 'POST /api/unterkunft/unterkuenfte/u1/ical-importe': () => ({ status: 201, body: {} }), 'DELETE /api/unterkunft/unterkuenfte/u1/ical-importe/i1': () => ({ body: {} }), 'POST /api/unterkunft/unterkuenfte/u1/ical-export/erneuern': () => ({ body: {} }), }), async (fx) => { const { panel } = await zeigeTab(fx, ukTab) await fx.klick(aktion(fx, panel, 'bearbeiten')) await fx.ruhe() await fx.setze(fx.finde(panel, '#bk-i-name'), 'Vrbo') await fx.setze(fx.finde(panel, '#bk-i-url'), 'http://unsicher.test/x.ics') const vorher = posts(fx).length await fx.klick(aktion(fx, panel, 'import-dazu')) assert.equal(posts(fx).length, vorher, 'nur https') await fx.setze(fx.finde(panel, '#bk-i-url'), 'https://vrbo.test/x.ics') await fx.klick(aktion(fx, panel, 'import-dazu')) await fx.ruhe() assert.deepEqual(posts(fx).find((a) => a.url.includes('ical-importe')).body, { name: 'Vrbo', url: 'https://vrbo.test/x.ics' }) await fx.klick(fx.finde(fx.finde(panel, '[data-import="i1"]'), '[data-aktion="import-weg"]')) assert.equal(posts(fx).filter((a) => a.method === 'DELETE').length, 0) await fx.klick(aktion(fx, panel, 'import-weg-ok')) await fx.ruhe() assert.equal(posts(fx).find((a) => a.method === 'DELETE').url, '/api/unterkunft/unterkuenfte/u1/ical-importe/i1?projectId=p1') await fx.klick(aktion(fx, panel, 'export-erneuern')) assert.equal(posts(fx).filter((a) => a.url.includes('erneuern')).length, 0) await fx.klick(aktion(fx, panel, 'erneuern-ok')) await fx.ruhe() assert.equal(posts(fx).filter((a) => a.url.includes('erneuern')).length, 1) }))