import { test, expect } from "@playwright/test"; const privacyUrl = "https://www.tri-hub.de/datenschutz"; async function expectConsent(form) { const checkbox = form.locator('[name="consent"]'); await expect(checkbox).not.toBeChecked(); await expect(checkbox).toHaveAttribute("required", ""); const link = form.getByRole("link", { name: "Datenschutzbestimmungen", exact: true, }); await expect(link).toHaveAttribute("href", privacyUrl); await expect(link).toHaveCSS("font-weight", "700"); await expect(link).toHaveCSS("text-decoration-line", "underline"); return checkbox; } test("Landingpage: beide Formulare benötigen Datenschutz; Kontakt speichert Zustimmung", async ({ page, }) => { await page.goto("/index.html"); await expectConsent(page.locator("#reviewForm")); const form = page.locator("#contactForm"); const consent = await expectConsent(form); await form.locator('[name="name"]').fill("Datenschutz Test"); await form.locator('[name="email"]').fill("privacy@example.test"); await form.locator('[name="subject"]').fill("Eine Testanfrage"); await form .locator('[name="message"]') .fill("Eine ausreichend lange Testnachricht."); await form.locator('[type="submit"]').click(); expect( await consent.evaluate((element) => element.validity.valueMissing), ).toBe(true); await consent.check(); const response = page.waitForResponse((response) => response.url().endsWith("/api/nutrition-contact"), ); await form.locator('[type="submit"]').click(); const saved = await response; expect(saved.status()).toBe(201); expect(saved.request().postDataJSON().consent).toBe(true); await expect(consent).not.toBeChecked(); }); test("Buchungsdialog verlangt Datenschutz und übermittelt Zustimmung", async ({ page, }) => { await page.goto("/booking.html?id=ernaehrung-starter"); await page .getByRole("button", { name: "Jetzt buchen", exact: true }) .click(); const form = page.locator("dialog form"); const consent = await expectConsent(form); await form.locator('[name="name"]').fill("Datenschutz Test"); await form.locator('[name="email"]').fill("privacy@example.test"); await form.locator('[type="submit"]').click(); await expect(page.locator('[id$="booking-consent-error"]')).toContainText( "Datenschutzbestimmungen akzeptieren", ); await consent.check(); const response = page.waitForResponse((response) => response.url().endsWith("/api/bookings"), ); await form.locator('[type="submit"]').click(); const saved = await response; expect(saved.status()).toBe(201); expect(saved.request().postDataJSON().consent).toBe(true); }); test("Beraterkontakt hat eine separate verpflichtende Datenschutz-Zustimmung", async ({ page, }) => { await page.goto("/contact-test.html?berater-id=maren-hoffmann"); await page .getByRole("button", { name: "Berater kontaktieren", exact: true }) .click(); await expectConsent(page.locator("dialog form")); }); for (const width of [375, 1280]) { test(`Buchungsfenster: Checkbox und erste Textzeile auf gleicher Höhe (${width}px)`, async ({ page, }) => { await page.setViewportSize({ width, height: 900 }); await page.goto("/booking.html?id=ernaehrung-starter"); await page .getByRole("button", { name: "Jetzt buchen", exact: true }) .click(); const label = page.locator(".booking__consent"); const difference = await label.evaluate((element) => { const checkbox = element .querySelector("input") .getBoundingClientRect(); const text = element.querySelector("span"); const firstLineCenter = text.getBoundingClientRect().top + parseFloat(getComputedStyle(text).lineHeight) / 2; return Math.abs( checkbox.top + checkbox.height / 2 - firstLineCenter, ); }); expect(difference).toBeLessThanOrEqual(1); await expect(label.locator("a")).toHaveCSS( "color", "rgb(255, 255, 255)", ); }); }