feat(T02): Static pages – home, referenzen, kontakt, legal (impressum/datenschutz/agb)

This commit is contained in:
Implementation Engineer
2026-07-10 01:02:27 +02:00
parent e9da21b57e
commit db5080df48
15 changed files with 1618 additions and 109 deletions
+76
View File
@@ -0,0 +1,76 @@
import { describe, it, expect } from "vitest";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
describe("Home Page", () => {
const pagePath = resolve(__dirname, "../../pages/index.vue");
const content = readFileSync(pagePath, "utf-8");
it("should render hero with headline 'Veranstaltungstechnik'", () => {
expect(content).toContain("Veranstaltungstechnik");
expect(content).toContain('data-testid="hero-headline"');
});
it("should have CTA button linking to /mietkatalog", () => {
expect(content).toContain('to="/mietkatalog"');
expect(content).toContain("Mietkatalog");
});
it("should have CTA button linking to /kontakt", () => {
expect(content).toContain('to="/kontakt"');
expect(content).toContain("Beratung anfragen");
});
it("should display all 8 services", () => {
expect(content).toContain("Vermietung");
expect(content).toContain("Verkauf");
expect(content).toContain("Personal");
expect(content).toContain("Transport");
expect(content).toContain("Lagerung");
expect(content).toContain("Werkstatt");
expect(content).toContain("Installation");
expect(content).toContain("Booking");
});
it("should have services section with data-testid", () => {
expect(content).toContain('data-testid="services-section"');
});
it("should have speaker grid with 6 equipment types", () => {
expect(content).toContain('data-testid="speaker-grid"');
expect(content).toContain("Lautsprecher");
expect(content).toContain("Mischpulte");
expect(content).toContain("Lichtanlagen");
expect(content).toContain("Rigging");
expect(content).toContain("Traversen");
expect(content).toContain("Komplett-Setups");
});
it("should have about section with stats", () => {
expect(content).toContain('data-testid="about-section"');
expect(content).toContain('data-testid="stat-years"');
expect(content).toContain("20+");
expect(content).toContain('data-testid="stat-devices"');
expect(content).toContain("1000+");
expect(content).toContain('data-testid="stat-events"');
expect(content).toContain("500+");
});
it("should have mietkatalog CTA section", () => {
expect(content).toContain('data-testid="mietkatalog-cta"');
expect(content).toContain('data-testid="cta-mietkatalog-link"');
});
it("should use TypeScript with lang=ts", () => {
expect(content).toContain('<script setup lang="ts">');
});
it("should use Tailwind classes, no inline styles", () => {
expect(content).not.toContain('style="');
});
it("should use useHead for page title", () => {
expect(content).toContain("useHead");
expect(content).toContain("HMS Licht");
});
});
+112
View File
@@ -0,0 +1,112 @@
import { describe, it, expect } from "vitest";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
describe("Kontakt Page", () => {
const pagePath = resolve(__dirname, "../../pages/kontakt.vue");
const content = readFileSync(pagePath, "utf-8");
it("should have page title Kontakt", () => {
expect(content).toContain("Kontakt");
});
it("should have office address card with Leipheim address", () => {
expect(content).toContain('data-testid="office-card"');
expect(content).toContain("Grockelhofen 10");
expect(content).toContain("89340 Leipheim");
});
it("should have warehouse address card with Ellzee", () => {
expect(content).toContain('data-testid="warehouse-card"');
expect(content).toContain("Ellzee");
});
it("should have opening hours card", () => {
expect(content).toContain('data-testid="hours-card"');
expect(content).toContain("Öffnungszeiten");
});
it("should have 2 contact persons", () => {
expect(content).toContain("Markus Hammerschmidt");
expect(content).toContain("Thomas Mössle");
});
it("should have form with name field (required)", () => {
expect(content).toContain('data-testid="form-name"');
expect(content).toContain("Name *");
});
it("should have form with email field (required)", () => {
expect(content).toContain('data-testid="form-email"');
expect(content).toContain("E-Mail *");
});
it("should have form with phone field (optional)", () => {
expect(content).toContain('data-testid="form-phone"');
expect(content).toContain("Telefon");
});
it("should have form with message field (required)", () => {
expect(content).toContain('data-testid="form-message"');
expect(content).toContain("Nachricht *");
});
it("should have form with privacy consent checkbox (required)", () => {
expect(content).toContain('data-testid="form-privacy"');
expect(content).toContain('type="checkbox"');
expect(content).toContain("Datenschutzerklärung");
});
it("should have submit button", () => {
expect(content).toContain('data-testid="form-submit"');
expect(content).toContain("Anfrage senden");
});
it("should have email validation with regex", () => {
expect(content).toContain("emailRegex");
expect(content).toContain("emailRegex.test");
});
it("should block submit when email is empty (validation error)", () => {
expect(content).toContain('data-testid="error-email"');
expect(content).toContain("Bitte geben Sie Ihre E-Mail-Adresse ein");
});
it("should block submit when privacy consent unchecked (validation error)", () => {
expect(content).toContain('data-testid="error-privacy"');
expect(content).toContain("Bitte stimmen Sie der Datenschutzerklärung zu");
});
it("should have validateField function", () => {
expect(content).toContain("validateField");
expect(content).toContain("validateAll");
});
it("should POST to /api/contact on submit", () => {
expect(content).toContain("$fetch");
expect(content).toContain("/api/contact");
expect(content).toContain("POST");
});
it("should have success state", () => {
expect(content).toContain('data-testid="success-message"');
expect(content).toContain("Vielen Dank");
});
it("should have error state", () => {
expect(content).toContain('data-testid="error-message"');
expect(content).toContain("Fehler");
});
it("should use TypeScript with lang=ts", () => {
expect(content).toContain('<script setup lang="ts">');
});
it("should use Tailwind classes, no inline styles", () => {
expect(content).not.toContain('style="');
});
it("should use useHead for page title", () => {
expect(content).toContain("useHead");
});
});
@@ -0,0 +1,89 @@
import { describe, it, expect } from "vitest";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
describe("Referenzen Page", () => {
const pagePath = resolve(__dirname, "../../pages/referenzen.vue");
const content = readFileSync(pagePath, "utf-8");
it("should have page title Referenzen", () => {
expect(content).toContain("Referenzen");
});
it("should have 9 gallery images", () => {
expect(content).toContain('data-testid="gallery-grid"');
const matches = content.match(/picsum\.photos/g);
expect(matches).not.toBeNull();
expect(matches!.length).toBe(9);
});
it("should have 4 category filter chips", () => {
expect(content).toContain('data-testid="filter-chips"');
expect(content).toContain("Alle");
expect(content).toContain("Open-Air");
expect(content).toContain("Indoor");
expect(content).toContain("Rigging");
});
it("should have Lightbox component", () => {
expect(content).toContain("Lightbox");
expect(content).toContain(':is-open="lightboxOpen"');
expect(content).toContain('@close="closeLightbox"');
expect(content).toContain('@prev="prevImage"');
expect(content).toContain('@next="nextImage"');
});
it("should have filter logic with computed filteredImages", () => {
expect(content).toContain("filteredImages");
expect(content).toContain("activeFilter");
expect(content).toContain("computed");
});
it("should have openLightbox function", () => {
expect(content).toContain("openLightbox");
expect(content).toContain("currentIndex");
});
it("should use TypeScript with lang=ts", () => {
expect(content).toContain('<script setup lang="ts">');
});
it("should use Tailwind classes, no inline styles", () => {
expect(content).not.toContain('style="');
});
it("should use useHead for page title", () => {
expect(content).toContain("useHead");
});
});
describe("Lightbox Component", () => {
const componentPath = resolve(__dirname, "../../components/Lightbox.vue");
const content = readFileSync(componentPath, "utf-8");
it("should have close button with data-testid", () => {
expect(content).toContain('data-testid="lightbox-close"');
});
it("should have prev button with data-testid", () => {
expect(content).toContain('data-testid="lightbox-prev"');
});
it("should have next button with data-testid", () => {
expect(content).toContain('data-testid="lightbox-next"');
});
it("should have data-testid lightbox", () => {
expect(content).toContain('data-testid="lightbox"');
});
it("should emit close, prev, next events", () => {
expect(content).toContain("close");
expect(content).toContain("prev");
expect(content).toContain("next");
});
it("should use TypeScript with lang=ts", () => {
expect(content).toContain('<script setup lang="ts">');
});
});