T01: Frontend Foundation – Nuxt 3 + Tailwind + Design Tokens + Layout + Meta
- Nuxt 3 project with @nuxtjs/tailwindcss module - Tailwind CSS config with A0 Dark Theme design tokens (CSS custom properties) - AppHeader: sticky, logo, nav, phone, social icons, mobile burger menu - AppFooter: 4-column grid (Navigation, Kontakt, Rechtliches, Social) - HmsLogo: SVG with orange #EC6925 border - error.vue: 404 page with Seite nicht gefunden - robots.txt server route: Disallow: / - Meta: noindex, nofollow, noarchive, nosnippet - JSON-LD: LocalBusiness schema - OpenGraph tags - routeRules: SSR/CSR per route - Shared components: LoadingSkeleton, EmptyState, ErrorState, LegalContentPage, SpeakerIcon - 42 vitest tests passing - Build: 0 errors
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
|
||||
test.describe("Error Pages", () => {
|
||||
test("404 page should show 'Seite nicht gefunden'", async ({ page }) => {
|
||||
const response = await page.goto("/nicht-existent");
|
||||
expect(response?.status()).toBe(404);
|
||||
await expect(page.locator("body")).toContainText("Seite nicht gefunden");
|
||||
await expect(page.getByRole("link", { name: /Startseite/ })).toBeVisible();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,74 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
|
||||
test.describe("Header", () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto("/");
|
||||
});
|
||||
|
||||
test("should display sticky header with logo", async ({ page }) => {
|
||||
const header = page.locator("header");
|
||||
await expect(header).toBeVisible();
|
||||
await expect(header).toHaveClass(/sticky/);
|
||||
});
|
||||
|
||||
test("should have navigation items", async ({ page }) => {
|
||||
await expect(page.getByRole("navigation").filter({ hasText: "Home" })).toBeVisible();
|
||||
await expect(page.getByRole("link", { name: "Referenzen" })).toBeVisible();
|
||||
await expect(page.getByRole("link", { name: "Mietkatalog" })).toBeVisible();
|
||||
await expect(page.getByRole("link", { name: "Kontakt" })).toBeVisible();
|
||||
});
|
||||
|
||||
test("should have clickable phone link", async ({ page }) => {
|
||||
const phoneLink = page.locator('a[href="tel:+491726264796"]');
|
||||
await expect(phoneLink).toBeVisible();
|
||||
});
|
||||
|
||||
test("should have social icons", async ({ page }) => {
|
||||
await expect(page.locator('a[aria-label="Facebook"]')).toBeVisible();
|
||||
await expect(page.locator('a[aria-label="Instagram"]')).toBeVisible();
|
||||
});
|
||||
|
||||
test("should open mobile burger menu on click", async ({ page }) => {
|
||||
const burger = page.locator('button[aria-label="Menü öffnen/schließen"]');
|
||||
await expect(burger).toBeVisible();
|
||||
await burger.click();
|
||||
await expect(page.locator("#mobile-nav")).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Footer", () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto("/");
|
||||
});
|
||||
|
||||
test("should display footer with address", async ({ page }) => {
|
||||
const footer = page.locator("footer");
|
||||
await expect(footer).toBeVisible();
|
||||
await expect(footer).toContainText("Leipheim");
|
||||
await expect(footer).toContainText("89340");
|
||||
});
|
||||
|
||||
test("should have phone number", async ({ page }) => {
|
||||
await expect(page.locator('a[href="tel:+498221204433"]')).toBeVisible();
|
||||
});
|
||||
|
||||
test("should have email link", async ({ page }) => {
|
||||
await expect(page.locator('a[href="mailto:info@hms-licht-ton.de"]')).toBeVisible();
|
||||
});
|
||||
|
||||
test("should have legal links", async ({ page }) => {
|
||||
await expect(page.getByRole("link", { name: "Impressum" })).toBeVisible();
|
||||
await expect(page.getByRole("link", { name: "DSGVO" })).toBeVisible();
|
||||
await expect(page.getByRole("link", { name: "AGB Vermietung" })).toBeVisible();
|
||||
});
|
||||
|
||||
test("should NOT contain 'Neu in der Vermietung'", async ({ page }) => {
|
||||
const footer = page.locator("footer");
|
||||
await expect(footer).not.toContainText("Neu in der Vermietung");
|
||||
});
|
||||
|
||||
test("should NOT contain 'AGB Shop'", async ({ page }) => {
|
||||
const footer = page.locator("footer");
|
||||
await expect(footer).not.toContainText("AGB Shop");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
|
||||
test.describe("Meta and Robots", () => {
|
||||
test("robots.txt should contain Disallow: /", async ({ request }) => {
|
||||
const response = await request.get("/robots.txt");
|
||||
const text = await response.text();
|
||||
expect(text).toContain("User-agent: *");
|
||||
expect(text).toContain("Disallow: /");
|
||||
});
|
||||
|
||||
test("home page should have noindex meta tag", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
const robotsMeta = page.locator('meta[name="robots"]');
|
||||
await expect(robotsMeta).toHaveAttribute("content", /noindex/);
|
||||
await expect(robotsMeta).toHaveAttribute("content", /nofollow/);
|
||||
await expect(robotsMeta).toHaveAttribute("content", /noarchive/);
|
||||
await expect(robotsMeta).toHaveAttribute("content", /nosnippet/);
|
||||
});
|
||||
|
||||
test("home page should contain JSON-LD LocalBusiness", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
const jsonld = page.locator('script[type="application/ld+json"]');
|
||||
const content = await jsonld.textContent();
|
||||
expect(content).toContain("LocalBusiness");
|
||||
expect(content).toContain("Hammerschmidt");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user