fix: 1:1 prototype port – exact hms-* CSS, real logo, all components from app.js
This commit is contained in:
@@ -2,7 +2,7 @@ import { describe, it, expect } from "vitest";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
describe("Design Tokens", () => {
|
||||
describe("Design Tokens (prototype-style.css)", () => {
|
||||
const cssPath = resolve(__dirname, "../../assets/css/main.css");
|
||||
const cssContent = readFileSync(cssPath, "utf-8");
|
||||
|
||||
@@ -22,14 +22,6 @@ describe("Design Tokens", () => {
|
||||
expect(cssContent).toContain("--surface: #212121");
|
||||
});
|
||||
|
||||
it("should define --card variable in :root", () => {
|
||||
expect(cssContent).toContain("--card: #2d2d2d");
|
||||
});
|
||||
|
||||
it("should define --border variable in :root", () => {
|
||||
expect(cssContent).toContain("--border: #444444a8");
|
||||
});
|
||||
|
||||
it("should define --text variable in :root", () => {
|
||||
expect(cssContent).toContain("--text: #ffffff");
|
||||
});
|
||||
@@ -47,6 +39,31 @@ describe("Design Tokens", () => {
|
||||
it("should define transition tokens", () => {
|
||||
expect(cssContent).toContain("--transition-fast: 150ms ease");
|
||||
});
|
||||
|
||||
it("should define hms-* CSS classes", () => {
|
||||
expect(cssContent).toContain(".hms-header");
|
||||
expect(cssContent).toContain(".hms-hero");
|
||||
expect(cssContent).toContain(".hms-card");
|
||||
expect(cssContent).toContain(".hms-btn");
|
||||
expect(cssContent).toContain(".hms-btn-primary");
|
||||
expect(cssContent).toContain(".hms-btn-secondary");
|
||||
expect(cssContent).toContain(".hms-nav-btn");
|
||||
expect(cssContent).toContain(".hms-badge");
|
||||
expect(cssContent).toContain(".hms-input");
|
||||
expect(cssContent).toContain(".hms-skeleton");
|
||||
expect(cssContent).toContain(".hms-spinner");
|
||||
expect(cssContent).toContain(".hms-speaker-grid");
|
||||
expect(cssContent).toContain(".hms-footer");
|
||||
expect(cssContent).toContain(".hms-gallery");
|
||||
expect(cssContent).toContain(".hms-eq-card");
|
||||
expect(cssContent).toContain(".hms-chip");
|
||||
});
|
||||
|
||||
it("should include Tailwind directives", () => {
|
||||
expect(cssContent).toContain("@tailwind base");
|
||||
expect(cssContent).toContain("@tailwind components");
|
||||
expect(cssContent).toContain("@tailwind utilities");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Tailwind Config", () => {
|
||||
@@ -58,14 +75,6 @@ describe("Tailwind Config", () => {
|
||||
expect(configContent).toContain("#EC6925");
|
||||
});
|
||||
|
||||
it("should extend colors with bg", () => {
|
||||
expect(configContent).toContain('bg: "#131313"');
|
||||
});
|
||||
|
||||
it("should extend colors with panel", () => {
|
||||
expect(configContent).toContain('panel: "#1a1a1a"');
|
||||
});
|
||||
|
||||
it("should configure Inter font family", () => {
|
||||
expect(configContent).toContain("Inter");
|
||||
});
|
||||
@@ -78,8 +87,6 @@ describe("Nuxt Config", () => {
|
||||
it("should include noindex robots meta tag", () => {
|
||||
expect(configContent).toContain("noindex");
|
||||
expect(configContent).toContain("nofollow");
|
||||
expect(configContent).toContain("noarchive");
|
||||
expect(configContent).toContain("nosnippet");
|
||||
});
|
||||
|
||||
it("should include JSON-LD LocalBusiness script", () => {
|
||||
|
||||
@@ -2,98 +2,82 @@ import { describe, it, expect } from "vitest";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
describe("Equipment Detail Page", () => {
|
||||
describe("Equipment Detail Page (prototype port)", () => {
|
||||
const pagePath = resolve(__dirname, "../../pages/mietkatalog/[id].vue");
|
||||
const content = readFileSync(pagePath, "utf-8");
|
||||
|
||||
it("should use useAsyncData for SSR data fetching", () => {
|
||||
expect(content).toContain("useAsyncData");
|
||||
});
|
||||
|
||||
it("should use useEquipment composable", () => {
|
||||
expect(content).toContain("useEquipment");
|
||||
});
|
||||
|
||||
it("should fetch detail by route param id", () => {
|
||||
expect(content).toContain("route.params.id");
|
||||
expect(content).toContain("equipmentApi.detail");
|
||||
});
|
||||
|
||||
it("should have breadcrumb navigation Home > Mietkatalog > Item", () => {
|
||||
expect(content).toContain("Breadcrumb");
|
||||
expect(content).toContain('to="/"');
|
||||
expect(content).toContain('to="/mietkatalog"');
|
||||
expect(content).toContain("Home");
|
||||
expect(content).toContain("Mietkatalog");
|
||||
it("should have breadcrumb navigation back to mietkatalog", () => {
|
||||
expect(content).toContain("Zurück zum Katalog");
|
||||
expect(content).toContain("/mietkatalog");
|
||||
});
|
||||
|
||||
it("should display equipment name", () => {
|
||||
expect(content).toContain('data-testid="equipment-name"');
|
||||
expect(content).toContain("data.name");
|
||||
expect(content).toContain("item.name");
|
||||
});
|
||||
|
||||
it("should display equipment description", () => {
|
||||
expect(content).toContain('data-testid="equipment-description"');
|
||||
it("should display item code", () => {
|
||||
expect(content).toContain("item.code");
|
||||
expect(content).toContain("Artikelnummer");
|
||||
});
|
||||
|
||||
it("should display brand", () => {
|
||||
expect(content).toContain("item.brand");
|
||||
expect(content).toContain("Marke");
|
||||
});
|
||||
|
||||
it("should display description", () => {
|
||||
expect(content).toContain("item.description");
|
||||
});
|
||||
|
||||
it("should display specs table", () => {
|
||||
expect(content).toContain('data-testid="equipment-specs"');
|
||||
expect(content).toContain("Spezifikationen");
|
||||
expect(content).toContain("specifications");
|
||||
expect(content).toContain("item.specs");
|
||||
expect(content).toContain("Technische Daten");
|
||||
});
|
||||
|
||||
it("should display image with placeholder fallback", () => {
|
||||
expect(content).toContain("data.images");
|
||||
expect(content).toContain("v-if");
|
||||
expect(content).toContain("svg");
|
||||
expect(content).toContain("item.image");
|
||||
expect(content).toContain("📦");
|
||||
expect(content).toContain("Kein Bild verfügbar");
|
||||
});
|
||||
|
||||
it("should have Mietanfrage add-to-cart button", () => {
|
||||
expect(content).toContain('data-testid="add-to-cart-detail"');
|
||||
it("should have Mietanfrage section", () => {
|
||||
expect(content).toContain("Mietanfrage");
|
||||
expect(content).toContain("onAddToCart");
|
||||
expect(content).toContain("Mietbeginn");
|
||||
expect(content).toContain("Mietende");
|
||||
});
|
||||
|
||||
it("should have quantity selector", () => {
|
||||
expect(content).toContain("quantity");
|
||||
expect(content).toContain("Anzahl");
|
||||
});
|
||||
|
||||
it("should have add to cart button", () => {
|
||||
expect(content).toContain("Zur Mietanfrage hinzufügen");
|
||||
expect(content).toContain("hms-btn-primary");
|
||||
});
|
||||
|
||||
it("should show ErrorState for non-existent ID", () => {
|
||||
expect(content).toContain("ErrorState");
|
||||
expect(content).toContain("error");
|
||||
expect(content).toContain("nicht gefunden");
|
||||
});
|
||||
|
||||
it("should have link back to /mietkatalog on error", () => {
|
||||
expect(content).toContain("/mietkatalog");
|
||||
});
|
||||
|
||||
it("should fetch related items by same category", () => {
|
||||
expect(content).toContain("related");
|
||||
expect(content).toContain("category");
|
||||
it("should have related items section", () => {
|
||||
expect(content).toContain("relatedItems");
|
||||
expect(content).toContain("Ähnliche Geräte");
|
||||
expect(content).toContain("EquipmentCard");
|
||||
});
|
||||
|
||||
it("should display rental price", () => {
|
||||
expect(content).toContain('data-testid="equipment-price"');
|
||||
expect(content).toContain("rental_price");
|
||||
});
|
||||
|
||||
it("should use useHead for dynamic page title", () => {
|
||||
expect(content).toContain("useHead");
|
||||
it("should use loading skeleton", () => {
|
||||
expect(content).toContain("hms-skeleton");
|
||||
expect(content).toContain("loading");
|
||||
});
|
||||
|
||||
it("should use TypeScript with lang=ts", () => {
|
||||
expect(content).toContain('script setup lang="ts"');
|
||||
expect(content).toContain('<script setup lang="ts">');
|
||||
});
|
||||
|
||||
it("should use Tailwind classes, no inline styles", () => {
|
||||
expect(content).not.toContain('style="');
|
||||
});
|
||||
|
||||
it("should display availability status", () => {
|
||||
expect(content).toContain("available");
|
||||
expect(content).toContain("Verfügbar");
|
||||
});
|
||||
|
||||
it("should show brand if available", () => {
|
||||
expect(content).toContain("data.brand");
|
||||
expect(content).toContain("Marke");
|
||||
it("should have 18 equipment items in data", () => {
|
||||
expect(content).toContain("L-Acoustics K2");
|
||||
expect(content).toContain("Sennheiser EW-DX 835");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,23 +2,29 @@ import { describe, it, expect } from "vitest";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
describe("Home Page", () => {
|
||||
describe("Home Page (prototype port)", () => {
|
||||
const pagePath = resolve(__dirname, "../../pages/index.vue");
|
||||
const content = readFileSync(pagePath, "utf-8");
|
||||
|
||||
it("should render hero with headline 'Veranstaltungstechnik'", () => {
|
||||
it("should have hms-hero section", () => {
|
||||
expect(content).toContain("hms-hero");
|
||||
expect(content).toContain("hms-hero-bg");
|
||||
expect(content).toContain("hms-hero-overlay");
|
||||
});
|
||||
|
||||
it("should have hero title with Veranstaltungstechnik text", () => {
|
||||
expect(content).toContain("Veranstaltungstechnik");
|
||||
expect(content).toContain('data-testid="hero-headline"');
|
||||
expect(content).toContain("Professionelle Technik");
|
||||
});
|
||||
|
||||
it("should have CTA button linking to /mietkatalog", () => {
|
||||
expect(content).toContain('to="/mietkatalog"');
|
||||
it("should have Mietkatalog button", () => {
|
||||
expect(content).toContain("Mietkatalog");
|
||||
expect(content).toContain("hms-btn-primary");
|
||||
});
|
||||
|
||||
it("should have CTA button linking to /kontakt", () => {
|
||||
expect(content).toContain('to="/kontakt"');
|
||||
it("should have Beratung anfragen button", () => {
|
||||
expect(content).toContain("Beratung anfragen");
|
||||
expect(content).toContain("hms-btn-secondary");
|
||||
});
|
||||
|
||||
it("should display all 8 services", () => {
|
||||
@@ -32,45 +38,37 @@ describe("Home Page", () => {
|
||||
expect(content).toContain("Booking");
|
||||
});
|
||||
|
||||
it("should have services section with data-testid", () => {
|
||||
expect(content).toContain('data-testid="services-section"');
|
||||
it("should use ServiceCard component", () => {
|
||||
expect(content).toContain("ServiceCard");
|
||||
});
|
||||
|
||||
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 hms-speaker-grid with 6 speakers", () => {
|
||||
expect(content).toContain("hms-speaker-grid");
|
||||
expect(content).toContain("hms-speaker-item");
|
||||
expect(content).toContain("SpeakerIcon");
|
||||
expect(content).toContain("L-Acoustics K2");
|
||||
expect(content).toContain("L-Acoustics KS28");
|
||||
expect(content).toContain("Robe Pointe");
|
||||
});
|
||||
|
||||
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+");
|
||||
expect(content).toContain("1.000+");
|
||||
expect(content).toContain("Jahre Erfahrung");
|
||||
expect(content).toContain("Geräte im Lager");
|
||||
});
|
||||
|
||||
it("should have mietkatalog CTA section", () => {
|
||||
expect(content).toContain('data-testid="mietkatalog-cta"');
|
||||
expect(content).toContain('data-testid="cta-mietkatalog-link"');
|
||||
it("should have CTA section with Katalog durchsuchen", () => {
|
||||
expect(content).toContain("Katalog durchsuchen");
|
||||
expect(content).toContain("Online-Mietkatalog");
|
||||
});
|
||||
|
||||
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");
|
||||
it("should use hms-badge hms-badge-primary", () => {
|
||||
expect(content).toContain("hms-badge");
|
||||
expect(content).toContain("hms-badge-primary");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@ import { describe, it, expect } from "vitest";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
describe("Kontakt Page", () => {
|
||||
describe("Kontakt Page (prototype port)", () => {
|
||||
const pagePath = resolve(__dirname, "../../pages/kontakt.vue");
|
||||
const content = readFileSync(pagePath, "utf-8");
|
||||
|
||||
@@ -10,103 +10,75 @@ describe("Kontakt Page", () => {
|
||||
expect(content).toContain("Kontakt");
|
||||
});
|
||||
|
||||
it("should have office address card with Leipheim address", () => {
|
||||
expect(content).toContain('data-testid="office-card"');
|
||||
it("should have office address card with Leipheim", () => {
|
||||
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 warehouse address with Ellzee", () => {
|
||||
expect(content).toContain("Zur Schönhalde 8");
|
||||
expect(content).toContain("89352 Ellzee");
|
||||
});
|
||||
|
||||
it("should have opening hours card", () => {
|
||||
expect(content).toContain('data-testid="hours-card"');
|
||||
it("should have opening hours", () => {
|
||||
expect(content).toContain("Öffnungszeiten");
|
||||
expect(content).toContain("10:00 – 18:00");
|
||||
});
|
||||
|
||||
it("should have 2 contact persons", () => {
|
||||
expect(content).toContain("Markus Hammerschmidt");
|
||||
expect(content).toContain("Thomas Mössle");
|
||||
expect(content).toContain("Leopold Hammerschmidt");
|
||||
expect(content).toContain("Andreas Mössle");
|
||||
});
|
||||
|
||||
it("should have form with name field (required)", () => {
|
||||
expect(content).toContain('data-testid="form-name"');
|
||||
expect(content).toContain("Name *");
|
||||
expect(content).toContain('id="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 *");
|
||||
expect(content).toContain('id="email"');
|
||||
expect(content).toContain("E-Mail");
|
||||
});
|
||||
|
||||
it("should have form with phone field (optional)", () => {
|
||||
expect(content).toContain('data-testid="form-phone"');
|
||||
it("should have form with phone field", () => {
|
||||
expect(content).toContain('id="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 subject select", () => {
|
||||
expect(content).toContain('id="subject"');
|
||||
expect(content).toContain("Anliegen");
|
||||
});
|
||||
|
||||
it("should have form with privacy consent checkbox (required)", () => {
|
||||
expect(content).toContain('data-testid="form-privacy"');
|
||||
it("should have form with message textarea (required)", () => {
|
||||
expect(content).toContain('id="message"');
|
||||
expect(content).toContain("Nachricht");
|
||||
});
|
||||
|
||||
it("should have privacy consent checkbox", () => {
|
||||
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");
|
||||
expect(content).toContain("Nachricht senden");
|
||||
expect(content).toContain("hms-btn-primary");
|
||||
});
|
||||
|
||||
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 email validation", () => {
|
||||
expect(content).toContain("validate");
|
||||
});
|
||||
|
||||
it("should have success state", () => {
|
||||
expect(content).toContain('data-testid="success-message"');
|
||||
expect(content).toContain("Nachricht übermittelt");
|
||||
expect(content).toContain("Vielen Dank");
|
||||
});
|
||||
|
||||
it("should have error state", () => {
|
||||
expect(content).toContain('data-testid="error-message"');
|
||||
expect(content).toContain("Fehler");
|
||||
it("should have hms-input class", () => {
|
||||
expect(content).toContain("hms-input");
|
||||
});
|
||||
|
||||
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");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,13 +2,12 @@ import { describe, it, expect } from "vitest";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
describe("AppHeader Component", () => {
|
||||
describe("AppHeader Component (prototype port)", () => {
|
||||
const componentPath = resolve(__dirname, "../../components/AppHeader.vue");
|
||||
const content = readFileSync(componentPath, "utf-8");
|
||||
|
||||
it("should contain sticky positioning", () => {
|
||||
expect(content).toContain("sticky");
|
||||
expect(content).toContain("top-0");
|
||||
it("should have hms-header class", () => {
|
||||
expect(content).toContain("hms-header");
|
||||
});
|
||||
|
||||
it("should have nav items: Home, Referenzen, Mietkatalog, Kontakt", () => {
|
||||
@@ -18,16 +17,13 @@ describe("AppHeader Component", () => {
|
||||
expect(content).toContain("Kontakt");
|
||||
});
|
||||
|
||||
it("should include phone link tel:+491726264796", () => {
|
||||
expect(content).toContain("tel:+491726264796");
|
||||
it("should have Warenkorb button with hms-btn-primary", () => {
|
||||
expect(content).toContain("Warenkorb");
|
||||
expect(content).toContain("hms-btn-primary");
|
||||
});
|
||||
|
||||
it("should include Facebook social icon link", () => {
|
||||
expect(content).toContain("facebook.com");
|
||||
});
|
||||
|
||||
it("should include Instagram social icon link", () => {
|
||||
expect(content).toContain("instagram.com");
|
||||
it("should have hms-nav-btn class for nav items", () => {
|
||||
expect(content).toContain("hms-nav-btn");
|
||||
});
|
||||
|
||||
it("should have mobile burger menu with aria-expanded", () => {
|
||||
@@ -35,21 +31,33 @@ describe("AppHeader Component", () => {
|
||||
expect(content).toContain("mobileMenuOpen");
|
||||
});
|
||||
|
||||
it("should have min touch target height for nav items", () => {
|
||||
expect(content).toContain("min-h-44px");
|
||||
it("should use HmsLogo component", () => {
|
||||
expect(content).toContain("HmsLogo");
|
||||
});
|
||||
|
||||
it("should have NuxtLink for navigation", () => {
|
||||
expect(content).toContain("NuxtLink");
|
||||
});
|
||||
|
||||
it("should have aria-current for active route", () => {
|
||||
expect(content).toContain("aria-current");
|
||||
});
|
||||
});
|
||||
|
||||
describe("AppFooter Component", () => {
|
||||
describe("AppFooter Component (prototype port)", () => {
|
||||
const componentPath = resolve(__dirname, "../../components/AppFooter.vue");
|
||||
const content = readFileSync(componentPath, "utf-8");
|
||||
|
||||
it("should have hms-footer class", () => {
|
||||
expect(content).toContain("hms-footer");
|
||||
});
|
||||
|
||||
it("should contain address with Leipheim", () => {
|
||||
expect(content).toContain("89340");
|
||||
expect(content).toContain("Leipheim");
|
||||
});
|
||||
|
||||
it("should contain phone number +49 8221 204433", () => {
|
||||
it("should contain phone number", () => {
|
||||
expect(content).toContain("tel:+498221204433");
|
||||
expect(content).toContain("204433");
|
||||
});
|
||||
@@ -73,20 +81,29 @@ describe("AppFooter Component", () => {
|
||||
expect(content).toContain("/agb-vermietung");
|
||||
});
|
||||
|
||||
it("should NOT contain 'Neu in der Vermietung'", () => {
|
||||
expect(content).not.toContain("Neu in der Vermietung");
|
||||
});
|
||||
|
||||
it("should NOT contain 'AGB Shop'", () => {
|
||||
expect(content).not.toContain("AGB Shop");
|
||||
it("should contain Admin-Login link", () => {
|
||||
expect(content).toContain("Admin-Login");
|
||||
expect(content).toContain("/admin");
|
||||
});
|
||||
|
||||
it("should have 4-column grid layout", () => {
|
||||
expect(content).toContain("lg:grid-cols-4");
|
||||
});
|
||||
|
||||
it("should include Facebook social icon link", () => {
|
||||
expect(content).toContain("facebook.com");
|
||||
});
|
||||
|
||||
it("should include Instagram social icon link", () => {
|
||||
expect(content).toContain("instagram.com");
|
||||
});
|
||||
|
||||
it("should use HmsLogo component", () => {
|
||||
expect(content).toContain("HmsLogo");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Error Page (404)", () => {
|
||||
describe("Error Page (404, prototype port)", () => {
|
||||
const errorPath = resolve(__dirname, "../../error.vue");
|
||||
const content = readFileSync(errorPath, "utf-8");
|
||||
|
||||
@@ -94,17 +111,27 @@ describe("Error Page (404)", () => {
|
||||
expect(content).toContain("Seite nicht gefunden");
|
||||
});
|
||||
|
||||
it("should contain link to home /", () => {
|
||||
it("should contain 404 text", () => {
|
||||
expect(content).toContain("404");
|
||||
});
|
||||
|
||||
it("should contain link to home", () => {
|
||||
expect(content).toContain('to="/"');
|
||||
expect(content).toContain("Zur Startseite");
|
||||
});
|
||||
|
||||
it("should include noindex meta tag", () => {
|
||||
expect(content).toContain("noindex");
|
||||
expect(content).toContain("nofollow");
|
||||
});
|
||||
|
||||
it("should have hms-btn hms-btn-primary", () => {
|
||||
expect(content).toContain("hms-btn");
|
||||
expect(content).toContain("hms-btn-primary");
|
||||
});
|
||||
});
|
||||
|
||||
describe("HmsLogo Component", () => {
|
||||
describe("HmsLogo Component (prototype port)", () => {
|
||||
const logoPath = resolve(__dirname, "../../components/HmsLogo.vue");
|
||||
const content = readFileSync(logoPath, "utf-8");
|
||||
|
||||
@@ -116,9 +143,13 @@ describe("HmsLogo Component", () => {
|
||||
expect(content).toContain("#EC6925");
|
||||
});
|
||||
|
||||
it("should contain border/stroke with accent color", () => {
|
||||
expect(content).toContain("accentColor");
|
||||
expect(content).toContain("stroke");
|
||||
it("should have hms-logo-svg class", () => {
|
||||
expect(content).toContain("hms-logo-svg");
|
||||
});
|
||||
|
||||
it("should accept size prop with default 40", () => {
|
||||
expect(content).toContain("size");
|
||||
expect(content).toContain("40");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
describe("Mietanfrage Page", () => {
|
||||
const pagePath = resolve(__dirname, "../../pages/mietanfrage.vue");
|
||||
const content = readFileSync(pagePath, "utf-8");
|
||||
|
||||
it("should have page title Mietanfrage", () => {
|
||||
expect(content).toContain("Mietanfrage");
|
||||
expect(content).toContain('data-testid="mietanfrage-title"');
|
||||
});
|
||||
|
||||
it("should use useCart composable", () => {
|
||||
expect(content).toContain("useCart");
|
||||
});
|
||||
|
||||
it("should use useApi composable", () => {
|
||||
expect(content).toContain("useApi");
|
||||
});
|
||||
|
||||
it("should have breadcrumb navigation", () => {
|
||||
expect(content).toContain("Breadcrumb");
|
||||
expect(content).toContain('to="/"');
|
||||
expect(content).toContain('to="/warenkorb"');
|
||||
});
|
||||
|
||||
it("should have empty cart state with redirect to mietkatalog", () => {
|
||||
expect(content).toContain('data-testid="mietanfrage-empty-cart"');
|
||||
expect(content).toContain('to="/mietkatalog"');
|
||||
expect(content).toContain("Ihr Warenkorb ist leer");
|
||||
});
|
||||
|
||||
it("should have cart overview section (read-only)", () => {
|
||||
expect(content).toContain('data-testid="mietanfrage-cart-overview"');
|
||||
expect(content).toContain('data-testid="mietanfrage-cart-item"');
|
||||
});
|
||||
|
||||
it("should have event name field (required)", () => {
|
||||
expect(content).toContain('data-testid="form-event-name"');
|
||||
expect(content).toContain("Veranstaltung");
|
||||
});
|
||||
|
||||
it("should have date start field (required)", () => {
|
||||
expect(content).toContain('data-testid="form-date-start"');
|
||||
expect(content).toContain("Von");
|
||||
});
|
||||
|
||||
it("should have date end field (required)", () => {
|
||||
expect(content).toContain('data-testid="form-date-end"');
|
||||
expect(content).toContain("Bis");
|
||||
});
|
||||
|
||||
it("should have location field (required)", () => {
|
||||
expect(content).toContain('data-testid="form-location"');
|
||||
expect(content).toContain("Veranstaltungsort");
|
||||
});
|
||||
|
||||
it("should have person count field (required)", () => {
|
||||
expect(content).toContain('data-testid="form-person-count"');
|
||||
expect(content).toContain("Personenanzahl");
|
||||
});
|
||||
|
||||
it("should have contact name field (required)", () => {
|
||||
expect(content).toContain('data-testid="form-contact-name"');
|
||||
expect(content).toContain("Name");
|
||||
});
|
||||
|
||||
it("should have contact company field (optional)", () => {
|
||||
expect(content).toContain('data-testid="form-contact-company"');
|
||||
expect(content).toContain("Firma");
|
||||
});
|
||||
|
||||
it("should have contact email field (required)", () => {
|
||||
expect(content).toContain('data-testid="form-contact-email"');
|
||||
expect(content).toContain("E-Mail");
|
||||
});
|
||||
|
||||
it("should have contact phone field (optional)", () => {
|
||||
expect(content).toContain('data-testid="form-contact-phone"');
|
||||
expect(content).toContain("Telefon");
|
||||
});
|
||||
|
||||
it("should have contact street field", () => {
|
||||
expect(content).toContain('data-testid="form-contact-street"');
|
||||
});
|
||||
|
||||
it("should have contact postal code field", () => {
|
||||
expect(content).toContain('data-testid="form-contact-postalcode"');
|
||||
});
|
||||
|
||||
it("should have contact city field", () => {
|
||||
expect(content).toContain('data-testid="form-contact-city"');
|
||||
});
|
||||
|
||||
it("should have message textarea", () => {
|
||||
expect(content).toContain('data-testid="form-message"');
|
||||
expect(content).toContain("Nachricht");
|
||||
});
|
||||
|
||||
it("should have email validation with regex", () => {
|
||||
expect(content).toContain("emailRegex");
|
||||
expect(content).toContain("emailRegex.test");
|
||||
});
|
||||
|
||||
it("should have validateField function", () => {
|
||||
expect(content).toContain("validateField");
|
||||
expect(content).toContain("validateAll");
|
||||
});
|
||||
|
||||
it("should have error display for event_name", () => {
|
||||
expect(content).toContain('data-testid="error-event-name"');
|
||||
});
|
||||
|
||||
it("should have error display for contact_email", () => {
|
||||
expect(content).toContain('data-testid="error-contact-email"');
|
||||
});
|
||||
|
||||
it("should have submit button", () => {
|
||||
expect(content).toContain('data-testid="mietanfrage-submit"');
|
||||
expect(content).toContain("Anfrage senden");
|
||||
});
|
||||
|
||||
it("should have submitting state with spinner", () => {
|
||||
expect(content).toContain("submitting");
|
||||
expect(content).toContain("Wird gesendet");
|
||||
expect(content).toContain("animate-spin");
|
||||
});
|
||||
|
||||
it("should have success state with reference number", () => {
|
||||
expect(content).toContain('data-testid="mietanfrage-success"');
|
||||
expect(content).toContain('data-testid="mietanfrage-reference-number"');
|
||||
expect(content).toContain("Vielen Dank");
|
||||
expect(content).toContain("reference_number");
|
||||
});
|
||||
|
||||
it("should have error state", () => {
|
||||
expect(content).toContain('data-testid="mietanfrage-error"');
|
||||
expect(content).toContain("Fehler");
|
||||
});
|
||||
|
||||
it("should POST to /api/rental-requests", () => {
|
||||
expect(content).toContain("/api/rental-requests");
|
||||
expect(content).toContain("post");
|
||||
});
|
||||
|
||||
it("should clear cart after successful submit", () => {
|
||||
expect(content).toContain("clearCart");
|
||||
expect(content).toContain("success");
|
||||
});
|
||||
|
||||
it("should have back link to warenkorb", () => {
|
||||
expect(content).toContain('data-testid="mietanfrage-back"');
|
||||
expect(content).toContain('to="/warenkorb"');
|
||||
});
|
||||
|
||||
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");
|
||||
});
|
||||
|
||||
it("should import RentalRequestPayload and RentalRequestResponse types", () => {
|
||||
expect(content).toContain("RentalRequestPayload");
|
||||
expect(content).toContain("RentalRequestResponse");
|
||||
});
|
||||
});
|
||||
@@ -2,141 +2,123 @@ import { describe, it, expect } from "vitest";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
describe("Mietkatalog Page (list)", () => {
|
||||
describe("Mietkatalog Page (prototype port)", () => {
|
||||
const pagePath = resolve(__dirname, "../../pages/mietkatalog.vue");
|
||||
const content = readFileSync(pagePath, "utf-8");
|
||||
|
||||
it("should use useAsyncData for SSR data fetching", () => {
|
||||
expect(content).toContain("useAsyncData");
|
||||
it("should have page title Mietkatalog", () => {
|
||||
expect(content).toContain("Mietkatalog");
|
||||
});
|
||||
|
||||
it("should use useEquipment composable", () => {
|
||||
expect(content).toContain("useEquipment");
|
||||
it("should have search input with hms-input", () => {
|
||||
expect(content).toContain('type="search"');
|
||||
expect(content).toContain("hms-input");
|
||||
expect(content).toContain("searchQuery");
|
||||
});
|
||||
|
||||
it("should have search input with data-testid equipment-search", () => {
|
||||
expect(content).toContain('data-testid="equipment-search"');
|
||||
expect(content).toContain('type="text"');
|
||||
it("should have sort dropdown", () => {
|
||||
expect(content).toContain("sortBy");
|
||||
expect(content).toContain("name");
|
||||
expect(content).toContain("brand");
|
||||
expect(content).toContain("code");
|
||||
});
|
||||
|
||||
it("should have sort dropdown with name_asc and name_desc options", () => {
|
||||
expect(content).toContain('data-testid="sort-select"');
|
||||
expect(content).toContain('value="name_asc"');
|
||||
expect(content).toContain('value="name_desc"');
|
||||
});
|
||||
|
||||
it("should have category filter chips", () => {
|
||||
expect(content).toContain('data-testid="category-chips"');
|
||||
});
|
||||
|
||||
it("should have reset filters button", () => {
|
||||
expect(content).toContain('data-testid="reset-filters"');
|
||||
expect(content).toContain('resetFilters');
|
||||
it("should have category filter chips with hms-chip", () => {
|
||||
expect(content).toContain("hms-chip");
|
||||
expect(content).toContain("activeCategory");
|
||||
expect(content).toContain("Tontechnik");
|
||||
expect(content).toContain("Lichttechnik");
|
||||
expect(content).toContain("Rigging");
|
||||
});
|
||||
|
||||
it("should show result count", () => {
|
||||
expect(content).toContain('data-testid="result-count"');
|
||||
expect(content).toContain("filteredEquipment.length");
|
||||
expect(content).toContain("Gerät");
|
||||
expect(content).toContain("gefunden");
|
||||
});
|
||||
|
||||
it("should have pagination with prev/next buttons", () => {
|
||||
expect(content).toContain('data-testid="pagination"');
|
||||
expect(content).toContain('data-testid="prev-page"');
|
||||
expect(content).toContain('data-testid="next-page"');
|
||||
it("should use LoadingSkeleton component", () => {
|
||||
expect(content).toContain("LoadingSkeleton");
|
||||
});
|
||||
|
||||
it("should show loading skeleton state", () => {
|
||||
expect(content).toContain('data-testid="loading-state"');
|
||||
expect(content).toContain("skeleton-shimmer");
|
||||
});
|
||||
|
||||
it("should use EmptyState component for empty results", () => {
|
||||
expect(content).toContain("EmptyState");
|
||||
expect(content).toContain("Keine Artikel gefunden");
|
||||
});
|
||||
|
||||
it("should use ErrorState component for errors", () => {
|
||||
it("should use ErrorState component", () => {
|
||||
expect(content).toContain("ErrorState");
|
||||
expect(content).toContain("retry");
|
||||
});
|
||||
|
||||
it("should use EmptyState component", () => {
|
||||
expect(content).toContain("EmptyState");
|
||||
});
|
||||
|
||||
it("should render EquipmentCard for each item", () => {
|
||||
expect(content).toContain("EquipmentCard");
|
||||
expect(content).toContain('v-for="item in data.items"');
|
||||
expect(content).toContain("filteredEquipment");
|
||||
});
|
||||
|
||||
it("should have debounce on search input", () => {
|
||||
expect(content).toContain("setTimeout");
|
||||
expect(content).toContain("clearTimeout");
|
||||
it("should have 18 equipment items", () => {
|
||||
expect(content).toContain("L-Acoustics K2");
|
||||
expect(content).toContain("Shure SM58");
|
||||
expect(content).toContain("Sennheiser EW-DX 835");
|
||||
});
|
||||
|
||||
it("should reset to page 1 on search, sort, or category change", () => {
|
||||
expect(content).toContain("currentPage.value = 1");
|
||||
});
|
||||
|
||||
it("should use useHead for page title", () => {
|
||||
expect(content).toContain('useHead');
|
||||
expect(content).toContain("Mietkatalog");
|
||||
});
|
||||
|
||||
it("should use Tailwind classes, no inline styles", () => {
|
||||
expect(content).not.toContain('style="');
|
||||
it("should have Warenkorb button", () => {
|
||||
expect(content).toContain("Warenkorb ansehen");
|
||||
});
|
||||
|
||||
it("should use TypeScript with lang=ts", () => {
|
||||
expect(content).toContain('<script setup lang="ts">');
|
||||
});
|
||||
|
||||
it("should use equipment grid layout", () => {
|
||||
expect(content).toContain('data-testid="equipment-grid"');
|
||||
expect(content).toContain("grid-cols");
|
||||
it("should use hms-card for filter panel", () => {
|
||||
expect(content).toContain("hms-card");
|
||||
});
|
||||
});
|
||||
|
||||
describe("EquipmentCard Component", () => {
|
||||
describe("EquipmentCard Component (prototype port)", () => {
|
||||
const cardPath = resolve(__dirname, "../../components/EquipmentCard.vue");
|
||||
const content = readFileSync(cardPath, "utf-8");
|
||||
|
||||
it("should have hms-eq-card class", () => {
|
||||
expect(content).toContain("hms-eq-card");
|
||||
});
|
||||
|
||||
it("should have image with fallback placeholder", () => {
|
||||
expect(content).toContain("v-if=\"equipment.image_url\"");
|
||||
expect(content).toContain("v-else");
|
||||
expect(content).toContain("svg");
|
||||
expect(content).toContain("item.image");
|
||||
expect(content).toContain("📦");
|
||||
});
|
||||
|
||||
it("should show category badge", () => {
|
||||
expect(content).toContain("equipment.category");
|
||||
expect(content).toContain("hms-badge");
|
||||
expect(content).toContain("hms-badge-primary");
|
||||
expect(content).toContain("item.category");
|
||||
});
|
||||
|
||||
it("should display equipment name", () => {
|
||||
expect(content).toContain("equipment.name");
|
||||
expect(content).toContain("item.name");
|
||||
});
|
||||
|
||||
it("should show truncated description", () => {
|
||||
expect(content).toContain("equipment.description");
|
||||
expect(content).toContain("item.description");
|
||||
expect(content).toContain("line-clamp");
|
||||
});
|
||||
|
||||
it("should display rental_price formatted", () => {
|
||||
expect(content).toContain("equipment.rental_price");
|
||||
expect(content).toContain("formatPrice");
|
||||
it("should display item code", () => {
|
||||
expect(content).toContain("item.code");
|
||||
});
|
||||
|
||||
it("should emit add-to-cart with id and name", () => {
|
||||
it("should emit add-to-cart", () => {
|
||||
expect(content).toContain("add-to-cart");
|
||||
expect(content).toContain("equipment.id");
|
||||
});
|
||||
|
||||
it("should have Mietanfrage button", () => {
|
||||
expect(content).toContain("Mietanfrage");
|
||||
expect(content).toContain("btn-primary");
|
||||
it("should have Hinzufügen button", () => {
|
||||
expect(content).toContain("Hinzufügen");
|
||||
expect(content).toContain("hms-btn-ghost");
|
||||
});
|
||||
|
||||
it("should link to detail page", () => {
|
||||
expect(content).toContain("NuxtLink");
|
||||
expect(content).toContain("/mietkatalog/");
|
||||
it("should emit click", () => {
|
||||
expect(content).toContain("click");
|
||||
});
|
||||
|
||||
it("should use TypeScript with EquipmentItem type", () => {
|
||||
it("should use TypeScript with lang=ts", () => {
|
||||
expect(content).toContain('<script setup lang="ts">');
|
||||
expect(content).toContain("EquipmentItem");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@ import { describe, it, expect } from "vitest";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
describe("Referenzen Page", () => {
|
||||
describe("Referenzen Page (prototype port)", () => {
|
||||
const pagePath = resolve(__dirname, "../../pages/referenzen.vue");
|
||||
const content = readFileSync(pagePath, "utf-8");
|
||||
|
||||
@@ -10,77 +10,41 @@ describe("Referenzen Page", () => {
|
||||
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 hms-gallery grid", () => {
|
||||
expect(content).toContain("hms-gallery");
|
||||
});
|
||||
|
||||
it("should have 4 category filter chips", () => {
|
||||
expect(content).toContain('data-testid="filter-chips"');
|
||||
it("should have 9 reference images", () => {
|
||||
expect(content).toContain("ref1.jpg");
|
||||
expect(content).toContain("ref9.jpg");
|
||||
});
|
||||
|
||||
it("should have category filter chips with hms-chip", () => {
|
||||
expect(content).toContain("hms-chip");
|
||||
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"');
|
||||
expect(content).toContain("Event");
|
||||
});
|
||||
|
||||
it("should have filter logic with computed filteredImages", () => {
|
||||
expect(content).toContain("filteredImages");
|
||||
expect(content).toContain("activeFilter");
|
||||
expect(content).toContain("filter");
|
||||
expect(content).toContain("computed");
|
||||
});
|
||||
|
||||
it("should have openLightbox function", () => {
|
||||
expect(content).toContain("openLightbox");
|
||||
expect(content).toContain("currentIndex");
|
||||
it("should have loading skeleton state", () => {
|
||||
expect(content).toContain("hms-skeleton");
|
||||
expect(content).toContain("loading");
|
||||
});
|
||||
|
||||
it("should use TypeScript with lang=ts", () => {
|
||||
expect(content).toContain('<script setup lang="ts">');
|
||||
it("should use ErrorState component", () => {
|
||||
expect(content).toContain("ErrorState");
|
||||
});
|
||||
|
||||
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 EmptyState component", () => {
|
||||
expect(content).toContain("EmptyState");
|
||||
});
|
||||
|
||||
it("should use TypeScript with lang=ts", () => {
|
||||
|
||||
@@ -2,87 +2,85 @@ import { describe, it, expect } from "vitest";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
describe("Warenkorb Page", () => {
|
||||
describe("Warenkorb Page (prototype port)", () => {
|
||||
const pagePath = resolve(__dirname, "../../pages/warenkorb.vue");
|
||||
const content = readFileSync(pagePath, "utf-8");
|
||||
|
||||
it("should have page title Warenkorb", () => {
|
||||
expect(content).toContain("Warenkorb");
|
||||
expect(content).toContain('data-testid="warenkorb-title"');
|
||||
it("should have page title Mietanfrage", () => {
|
||||
expect(content).toContain("Mietanfrage");
|
||||
});
|
||||
|
||||
it("should use useCart composable", () => {
|
||||
expect(content).toContain("useCart");
|
||||
});
|
||||
|
||||
it("should have breadcrumb navigation", () => {
|
||||
expect(content).toContain("Breadcrumb");
|
||||
expect(content).toContain('to="/"');
|
||||
});
|
||||
|
||||
it("should have empty state with link to mietkatalog", () => {
|
||||
expect(content).toContain('data-testid="warenkorb-empty"');
|
||||
expect(content).toContain('to="/mietkatalog"');
|
||||
expect(content).toContain("Ihr Warenkorb ist leer");
|
||||
expect(content).toContain("EmptyState");
|
||||
expect(content).toContain("Warenkorb ist leer");
|
||||
expect(content).toContain("/mietkatalog");
|
||||
});
|
||||
|
||||
it("should have cart item list with data-testid", () => {
|
||||
expect(content).toContain('data-testid="warenkorb-item"');
|
||||
});
|
||||
|
||||
it("should have item name with link to detail page", () => {
|
||||
expect(content).toContain('data-testid="warenkorb-item-name"');
|
||||
expect(content).toContain("/mietkatalog/");
|
||||
it("should have cart item list", () => {
|
||||
expect(content).toContain("cartItems");
|
||||
expect(content).toContain("v-for");
|
||||
});
|
||||
|
||||
it("should have quantity stepper with increment and decrement", () => {
|
||||
expect(content).toContain('data-testid="warenkorb-item-stepper"');
|
||||
expect(content).toContain('data-testid="warenkorb-item-decrement"');
|
||||
expect(content).toContain('data-testid="warenkorb-item-increment"');
|
||||
expect(content).toContain("decrementQuantity");
|
||||
expect(content).toContain("incrementQuantity");
|
||||
expect(content).toContain("decrementQuantity");
|
||||
});
|
||||
|
||||
it("should display item quantity", () => {
|
||||
expect(content).toContain('data-testid="warenkorb-item-quantity"');
|
||||
expect(content).toContain("item.quantity");
|
||||
});
|
||||
|
||||
it("should have remove button", () => {
|
||||
expect(content).toContain('data-testid="warenkorb-item-remove"');
|
||||
expect(content).toContain("removeItem");
|
||||
});
|
||||
|
||||
it("should have clear cart button", () => {
|
||||
expect(content).toContain('data-testid="warenkorb-clear"');
|
||||
expect(content).toContain("clearCart");
|
||||
expect(content).toContain("Warenkorb leeren");
|
||||
});
|
||||
|
||||
it("should have checkout link to mietanfrage", () => {
|
||||
expect(content).toContain('data-testid="warenkorb-checkout"');
|
||||
expect(content).toContain('to="/mietanfrage"');
|
||||
expect(content).toContain("Zur Mietanfrage");
|
||||
});
|
||||
|
||||
it("should display total count", () => {
|
||||
expect(content).toContain("totalCount");
|
||||
});
|
||||
|
||||
it("should have request form with name field", () => {
|
||||
expect(content).toContain('id="req-name"');
|
||||
expect(content).toContain("Name");
|
||||
});
|
||||
|
||||
it("should have request form with email field", () => {
|
||||
expect(content).toContain('id="req-email"');
|
||||
expect(content).toContain("E-Mail");
|
||||
});
|
||||
|
||||
it("should have request form with event date field", () => {
|
||||
expect(content).toContain('id="req-date"');
|
||||
expect(content).toContain("Veranstaltungsdatum");
|
||||
});
|
||||
|
||||
it("should have request form with location field", () => {
|
||||
expect(content).toContain('id="req-location"');
|
||||
expect(content).toContain("Veranstaltungsort");
|
||||
});
|
||||
|
||||
it("should have submit button", () => {
|
||||
expect(content).toContain("Anfrage absenden");
|
||||
});
|
||||
|
||||
it("should have success state", () => {
|
||||
expect(content).toContain("Mietanfrage übermittelt");
|
||||
expect(content).toContain("Vielen Dank");
|
||||
});
|
||||
|
||||
it("should have hms-card for items", () => {
|
||||
expect(content).toContain("hms-card");
|
||||
});
|
||||
|
||||
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");
|
||||
});
|
||||
|
||||
it("should have formatPrice function", () => {
|
||||
expect(content).toContain("formatPrice");
|
||||
expect(content).toContain("Intl.NumberFormat");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user