import { expect, type APIRequestContext, type Page } from '@playwright/test'; import { SITE_CONFIG } from '../src/app/core/content/site-config'; import { SITE_CONTENT_DATA } from '../src/app/core/content/site-content'; import { type AppLocale } from '../src/app/core/i18n/locale'; import { LOCALE_HTML_LANG } from '../src/app/core/i18n/locale'; import { type RouteId } from '../src/app/core/routing/route-ids'; import { routePath } from '../src/app/core/routing/route-paths'; import { buildRouteMetadata } from '../src/app/core/seo/route-metadata'; export const ORIGIN = SITE_CONFIG.siteOrigin; export function pagePath(routeId: RouteId, locale: AppLocale): string { return routePath(routeId, locale); } export async function readHtml(request: APIRequestContext, path: string): Promise { const response = await request.get(path); expect(response.status(), `GET ${path} failed`).toBeLessThan(400); return response.text(); } export function attr(html: string, selector: string, attribute: string): string | null { const pattern = new RegExp( `<[^>]*${selector.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}[^>]*${attribute}="([^"]*)"`, 'i', ); return html.match(pattern)?.[1] ?? null; } export function count(html: string, snippet: string): number { return html.split(snippet).length - 1; } export async function expectHead( request: APIRequestContext, routeId: RouteId, locale: AppLocale, ): Promise { const path = routeId === 'notFound' ? locale === 'en' ? '/en/missing-route' : '/missing-route' : pagePath(routeId, locale); const html = await readHtml(request, path); const metadata = buildRouteMetadata(routeId, locale, SITE_CONTENT_DATA); expect(html, `${path} title`).toContain(`${metadata.title}`); expect(html).toContain(`name="description"`); expect(html).toContain(`content="${metadata.description}"`); expect(html).toContain(`name="robots"`); expect(html).toContain(`content="${metadata.robots}"`); expect(html).toContain(`]*hreflang/); return; } expect(html).toContain(`rel="canonical"`); expect(html).toContain(`href="${metadata.canonical}"`); expect(count(html, 'rel="canonical"')).toBe(1); expect(html).toContain('hreflang="de-DE"'); expect(html).toContain('hreflang="en"'); expect(html).toContain('hreflang="x-default"'); expect(html).toContain('property="og:type"'); expect(html).toContain('property="og:title"'); expect(html).toContain('property="og:description"'); expect(html).toContain('property="og:url"'); expect(html).toContain('property="og:site_name"'); expect(html).toContain('property="og:locale"'); expect(html).toContain('name="twitter:card"'); expect(html).toContain('name="twitter:title"'); expect(html).toContain('name="twitter:description"'); } export async function expectNoOverflow(page: Page): Promise { const overflow = await page.evaluate( () => document.documentElement.scrollWidth <= window.innerWidth + 1, ); expect(overflow, `horizontal overflow at ${page.url()}`).toBe(true); } export async function jsonLdGraph(page: Page): Promise { const raw = await page.locator('script[type="application/ld+json"]').first().textContent(); expect(raw).toBeTruthy(); return JSON.parse(raw ?? 'null'); }