Files
fotospiel-app/resources/js/layouts/__tests__/mainWebsite.seo.test.tsx
Codex Agent 1443ff0d3a
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
tests / ui (push) Has been cancelled
Add marketing hreflang tests and docs
2026-01-30 11:52:44 +01:00

148 lines
4.8 KiB
TypeScript

import React from 'react';
import { describe, expect, it, vi } from 'vitest';
import { render } from '@testing-library/react';
const page = {
url: '/de/kontakt',
props: {
locale: 'de',
supportedLocales: ['de', 'en'],
appUrl: 'https://fotospiel.app',
translations: {
marketing: {
title: 'Fotospiel',
description: 'Sammle Gastfotos für Events mit QR-Codes',
},
},
auth: {},
},
};
vi.mock('react-i18next', () => ({
useTranslation: () => ({
t: (key: string, fallback?: string | { defaultValue?: unknown }) => {
if (typeof fallback === 'string') {
return fallback;
}
if (fallback && typeof fallback === 'object' && 'defaultValue' in fallback) {
return fallback.defaultValue;
}
return key;
},
i18n: {
language: 'de',
changeLanguage: vi.fn(),
},
ready: true,
}),
}));
vi.mock('@inertiajs/react', async () => {
const ReactModule = await import('react');
const ReactDom = await import('react-dom');
return {
Head: ({ children }: { children?: React.ReactNode }) =>
ReactDom.createPortal(children, document.head),
Link: ({ children, href }: { children: React.ReactNode; href: string }) => (
<a href={href}>{children}</a>
),
router: {
post: vi.fn(),
visit: vi.fn(),
},
usePage: () => page,
};
});
vi.mock('@/components/analytics/MatomoTracker', () => ({
default: () => null,
}));
vi.mock('@/layouts/app/Footer', () => ({
default: () => null,
}));
vi.mock('@/hooks/use-appearance', () => ({
useAppearance: () => ({
appearance: 'light',
updateAppearance: vi.fn(),
}),
}));
vi.mock('@/components/ui/button', () => ({
Button: ({ children }: { children: React.ReactNode }) => <button type="button">{children}</button>,
}));
vi.mock('@/components/ui/dropdown-menu', () => ({
DropdownMenu: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
DropdownMenuContent: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
DropdownMenuItem: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
DropdownMenuLabel: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
DropdownMenuRadioGroup: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
DropdownMenuRadioItem: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
DropdownMenuSeparator: () => <div />,
DropdownMenuTrigger: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
}));
vi.mock('react-hot-toast', () => ({
default: {
success: vi.fn(),
},
}));
vi.mock('lucide-react', () => ({
MoreHorizontal: () => null,
Sun: () => null,
Moon: () => null,
Languages: () => null,
LayoutDashboard: () => null,
LogOut: () => null,
LogIn: () => null,
}));
import MarketingLayout from '../mainWebsite';
describe('MarketingLayout SEO tags', () => {
it('renders canonical and hreflang links for the active locale', () => {
page.url = '/de/kontakt';
page.props.locale = 'de';
render(
<MarketingLayout title="Kontakt">
<div>Test</div>
</MarketingLayout>
);
const canonical = document.head.querySelector('link[rel="canonical"]');
const alternateDe = document.head.querySelector('link[rel="alternate"][hreflang="de"]');
const alternateEn = document.head.querySelector('link[rel="alternate"][hreflang="en"]');
const alternateDefault = document.head.querySelector('link[rel="alternate"][hreflang="x-default"]');
expect(canonical).toHaveAttribute('href', 'https://fotospiel.app/de/kontakt');
expect(alternateDe).toHaveAttribute('href', 'https://fotospiel.app/de/kontakt');
expect(alternateEn).toHaveAttribute('href', 'https://fotospiel.app/en/contact');
expect(alternateDefault).toHaveAttribute('href', 'https://fotospiel.app/de/kontakt');
});
it('preserves query params and rewrites localized slugs across locales', () => {
page.url = '/en/contact?ref=ad';
page.props.locale = 'en';
render(
<MarketingLayout title="Contact">
<div>Test</div>
</MarketingLayout>
);
const canonical = document.head.querySelector('link[rel="canonical"]');
const alternateDe = document.head.querySelector('link[rel="alternate"][hreflang="de"]');
const alternateEn = document.head.querySelector('link[rel="alternate"][hreflang="en"]');
const alternateDefault = document.head.querySelector('link[rel="alternate"][hreflang="x-default"]');
expect(canonical).toHaveAttribute('href', 'https://fotospiel.app/en/contact?ref=ad');
expect(alternateEn).toHaveAttribute('href', 'https://fotospiel.app/en/contact?ref=ad');
expect(alternateDe).toHaveAttribute('href', 'https://fotospiel.app/de/kontakt?ref=ad');
expect(alternateDefault).toHaveAttribute('href', 'https://fotospiel.app/de/kontakt?ref=ad');
});
});