From 2df56eccc5820cbb733cfc354b2c7e7b71cddc77 Mon Sep 17 00:00:00 2001 From: Kenso Grimm Date: Wed, 7 Oct 2026 15:10:00 +0000 Subject: [PATCH] =?UTF-8?q?Buchungskalender:=20UI-Durchlauf=20=E2=80=93=20?= =?UTF-8?q?Screenshots=20wie=20im=20Webshop,=20Sichtbarkeitspr=C3=BCfung?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- test/ui/unterkunft.ui.mjs | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/test/ui/unterkunft.ui.mjs b/test/ui/unterkunft.ui.mjs index 6ec9459..414dac7 100644 --- a/test/ui/unterkunft.ui.mjs +++ b/test/ui/unterkunft.ui.mjs @@ -59,11 +59,17 @@ let nummer = 0 /** Screenshot der ganzen Seite in der aktuellen Fensterbreite (Name: fortlaufende Nummer, Beschreibung, Breite). */ async function shot(page, name) { nummer += 1 - const breite = page.viewportSize().width + const vorher = page.viewportSize() + const breite = vorher.width await page.evaluate(() => Promise.all(document.getAnimations().filter((a) => a.effect.getComputedTiming().iterations !== Infinity).map((a) => a.finished.catch(() => {})))).catch(() => {}) await page.waitForTimeout(150) + // wie test/ui/shop.ui.mjs: Fenster auf Seitenhoehe stellen statt fullPage (die Portalansicht blendet sonst leer ein) + const hoehe = await page.evaluate(() => Math.min(Math.max(document.documentElement.scrollHeight, window.innerHeight), 3600)) + await page.setViewportSize({ width: breite, height: hoehe }) + await page.waitForTimeout(100) const datei = `${SHOTS}/${String(nummer).padStart(2, '0')}-${name}-${breite}.png` - await page.screenshot({ path: datei, fullPage: true }) + await page.screenshot({ path: datei }) + await page.setViewportSize(vorher) return datei } /** Dieselbe Seite zusaetzlich in der anderen Breite aufnehmen und zurueckstellen. */ @@ -174,14 +180,27 @@ async function lauf(name, fn) { // ---------------------------------------------------------------- Portal-Helfer +/** Sichtbarkeit wirklich pruefen (nicht nur DOM): sichtbar, Hoehe > 0, nicht durchsichtig (Einblend-Animation fertig). */ +async function sichtbar(locator, name) { + await warteBis(async () => { + if (!(await locator.first().isVisible().catch(() => false))) return false + const box = await locator.first().boundingBox() + const deckend = await locator.first().evaluate((el) => { let o = 1; for (let e = el; e; e = e.parentElement) o *= Number(getComputedStyle(e).opacity); return o > 0.99 }) + return Boolean(box) && box.height > 0 && box.width > 0 && deckend + }, `${name} sichtbar`, 5000).catch(() => ok(false, `${name} ist nicht sichtbar (Hoehe 0, hidden oder durchsichtig)`)) +} const oeffnePortal = async (page) => { await page.goto(`${srv.portalUrl}/dashboard.html#buchungen`) await page.locator('#view-buchungen.active').waitFor() await page.locator('#buchungen-body .sh-reiterleiste').waitFor() + await sichtbar(page.locator('#view-buchungen'), 'Ansicht Buchungskalender') + await sichtbar(page.locator('#view-buchungen h1'), 'Titel Buchungskalender') + await sichtbar(page.locator('[data-reiter="anfragen"]'), 'Reiter Anfragen') } const reiter = async (page, key) => { await page.locator(`[data-reiter="${key}"]`).click() await page.locator(`#bk-tab-${key}[aria-selected="true"]`).waitFor() + await sichtbar(page.locator('#bk-panel > *'), `Inhalt des Reiters ${key}`) } const warteMeldung = async (page, teil) => { await warteBis(async () => enthaelt(await page.locator('#buchungen-body .sh-meldung').innerText().catch(() => ''), teil), `Meldung „${teil}“`) @@ -308,7 +327,16 @@ async function szenario() { await portal.locator('#bk-p-ust-re').fill('19') await portal.locator('#bk-p-frist').fill('3') await portal.locator('[data-aktion="storno-muster"]').click() - ok((await portal.locator('#bk-p-storno').inputValue()).startsWith('1. Stornierung durch den Gast.'), 'Mustertext in die Stornobedingungen übernommen') + const muster = await portal.locator('#bk-p-storno').inputValue() + ok(muster.startsWith('1. Stornierung durch den Gast.'), 'Mustertext in die Stornobedingungen übernommen') + // mit den Platzhaltern wird nicht gespeichert + await portal.locator('[data-aktion="preise-speichern"]').click() + await warteBis(async () => enthaelt(await portal.locator('[data-fehler="stornobedingungen"]').innerText(), 'Bitte ersetze die Platzhalter in eckigen Klammern durch deine Werte.'), 'Platzhalter-Fehler am Feld') + ok(srv.preise().length === 0, 'Preise mit Platzhaltern nicht gespeichert') + await shot(portal, 'preise-platzhalter-fehler') + // Platzhalter durch Werte ersetzen + await portal.locator('#bk-p-storno').fill(muster.replace('[E-Mail-Adresse des Vermieters]', 'buchung@donau-home.example').replace(/\[(\d+)\]/g, '$1')) + ok(!/\[[^\]]*\]/.test(await portal.locator('#bk-p-storno').inputValue()), 'keine eckigen Klammern mehr in den Stornobedingungen') await shot(portal, 'preise-ausgefuellt') await portal.locator('[data-aktion="preise-speichern"]').click() await warteMeldung(portal, 'Die Preise sind gespeichert')