import { test, expect, waitForSpaReady, navigateToRoute, clickSpaLink } from "./fixtures" /** * Helper: Force all scroll-reveal elements to be visible. * The `.reveal` class starts with opacity:0 and only animates in * when the IntersectionObserver fires — which doesn't happen * reliably in headless Playwright screenshots/assertions. */ async function revealAll(page: import("@playwright/test").Page) { await page.evaluate(() => document.querySelectorAll(".reveal").forEach((e) => e.classList.add("revealed"))) } test.describe("Demo — Homepage", () => { test.beforeEach(async ({ page }) => { await page.goto("/de/") await waitForSpaReady(page) await revealAll(page) }) test("should render hero section with headline and CTA", async ({ page }) => { const hero = page.locator("[data-block='hero']").first() await expect(hero).toBeVisible() const h1 = hero.locator("h1") await expect(h1).toBeVisible() await expect(h1).not.toBeEmpty() const cta = hero.locator("a[href*='#']") await expect(cta).toBeVisible() }) test("should render features section with cards", async ({ page }) => { const features = page.locator("[data-block='features']") await expect(features).toBeVisible() const heading = features.locator("h2") await expect(heading).toBeVisible() const cards = features.locator(".feature-card") await expect(cards).toHaveCount(6) }) test("should render richtext section with image", async ({ page }) => { const richtext = page.locator("[data-block='richtext']").first() await expect(richtext).toBeVisible() const img = richtext.locator("img") await expect(img).toBeVisible() }) test("should render accordion with expandable items", async ({ page }) => { const accordion = page.locator("[data-block='accordion']") await expect(accordion).toBeVisible() const buttons = accordion.locator("button") const count = await buttons.count() expect(count).toBeGreaterThanOrEqual(3) // First item should be expanded by default const firstButton = buttons.first() await expect(firstButton).toHaveAttribute("aria-expanded", "true") // Click a collapsed item to expand it const secondButton = buttons.nth(1) await expect(secondButton).toHaveAttribute("aria-expanded", "false") await secondButton.click() await expect(secondButton).toHaveAttribute("aria-expanded", "true") }) test("should have footer with navigation and language selector", async ({ page }) => { const footer = page.locator("footer") await expect(footer).toBeVisible() const navLinks = footer.locator("nav a, ul a") const linkCount = await navLinks.count() expect(linkCount).toBeGreaterThanOrEqual(3) // Language links in footer const deLangLink = footer.locator('a:has-text("Deutsch")') const enLangLink = footer.locator('a:has-text("English")') await expect(deLangLink).toBeVisible() await expect(enLangLink).toBeVisible() }) }) test.describe("Demo — About Page", () => { test("should load about page with hero and content", async ({ page }) => { await page.goto("/en/about") await waitForSpaReady(page) await revealAll(page) const hero = page.locator("[data-block='hero']").first() await expect(hero).toBeVisible() const h1 = hero.locator("h1") await expect(h1).toContainText("About") const richtextBlocks = page.locator("[data-block='richtext']") const count = await richtextBlocks.count() expect(count).toBeGreaterThanOrEqual(2) }) }) test.describe("Demo — Contact Page", () => { test("should load contact page with form", async ({ page }) => { await page.goto("/en/contact") await waitForSpaReady(page) await revealAll(page) const hero = page.locator("[data-block='hero']").first() await expect(hero).toBeVisible() const form = page.locator("[data-block='contact-form']") await expect(form).toBeVisible() }) test("should have all form fields", async ({ page }) => { await page.goto("/en/contact") await waitForSpaReady(page) await revealAll(page) await expect(page.getByLabel("Name")).toBeVisible() await expect(page.getByLabel("Email")).toBeVisible() await expect(page.locator("select, [role='combobox']").first()).toBeVisible() await expect(page.getByLabel("Message")).toBeVisible() await expect(page.locator("button[type='submit'], button:has-text('Send')")).toBeVisible() }) test("should validate required fields", async ({ page }) => { await page.goto("/en/contact") await waitForSpaReady(page) await revealAll(page) // Click send without filling fields const submitBtn = page.locator("button[type='submit'], button:has-text('Send')").first() await submitBtn.click() // Should show validation errors (form stays, no success toast) await expect(page.locator("[data-block='contact-form']")).toBeVisible() }) }) test.describe("Demo — Navigation", () => { test("should navigate between pages via header links", async ({ page }) => { await page.goto("/en/") await waitForSpaReady(page) // Navigate to About await page.locator('header nav a[href*="/about"]').click() await page.waitForLoadState("domcontentloaded") expect(page.url()).toContain("/about") await expect(page.locator("[data-block='hero'] h1")).toContainText("About") // Navigate to Contact await page.locator('header nav a[href*="/contact"]').click() await page.waitForLoadState("domcontentloaded") expect(page.url()).toContain("/contact") await expect(page.locator("[data-block='hero'] h1")).toContainText("Contact") // Navigate back to Home await page.locator('header a[href="/en"]').first().click() await page.waitForLoadState("domcontentloaded") expect(page.url()).toMatch(/\/en\/?$/) }) test("should switch language with route translation", async ({ page }) => { // Start on English about page await page.goto("/en/about") await waitForSpaReady(page) expect(page.url()).toContain("/en/about") // Click German language link — should translate route to /de/ueber-uns const deLink = page.locator('a[href*="/de/ueber-uns"]').first() await expect(deLink).toBeVisible() await deLink.click() await page.waitForLoadState("domcontentloaded") expect(page.url()).toContain("/de/ueber-uns") // Verify hero updated to German await expect(page.locator("[data-block='hero'] h1")).toBeVisible() }) test("should switch language on contact page with route translation", async ({ page }) => { await page.goto("/en/contact") await waitForSpaReady(page) const deLink = page.locator('a[href*="/de/kontakt"]').first() await expect(deLink).toBeVisible() await deLink.click() await page.waitForLoadState("domcontentloaded") expect(page.url()).toContain("/de/kontakt") }) }) test.describe("Demo — 404 Page", () => { test("should show 404 for unknown routes", async ({ page }) => { await page.goto("/en/nonexistent-page") await waitForSpaReady(page) await expect(page.locator("text=404")).toBeVisible() await expect(page.locator("h1")).toContainText("Page not found") // Use the specific "Back to Home" link in the 404 main content, not header/footer const homeLink = page.getByRole("link", { name: "Back to Home" }) await expect(homeLink).toBeVisible() }) test("should navigate back from 404 to home", async ({ page }) => { await page.goto("/en/nonexistent-page") await waitForSpaReady(page) const homeLink = page.getByRole("link", { name: "Back to Home" }) await homeLink.click() await page.waitForLoadState("domcontentloaded") expect(page.url()).toMatch(/\/en\/?$/) await expect(page.locator("[data-block='hero']")).toBeVisible() }) })