import { expect, test } from '@playwright/test'; import { SITE_CONFIG } from '../src/app/core/content/site-config'; import { expectNoOverflow, pagePath } from './helpers'; const CHECKED = [ pagePath('home', 'de'), pagePath('home', 'en'), pagePath('projects', 'de'), pagePath('projects', 'en'), pagePath('servicesAi', 'de'), pagePath('contact', 'de'), pagePath('imprint', 'en'), '/missing-route', ]; test.describe('layout and crawlability', () => { test('does not overflow horizontally on checked routes', async ({ page }) => { for (const path of CHECKED) { await page.goto(path); await expectNoOverflow(page); } }); test('same-origin links and crawl files respond below 400', async ({ page, request }) => { const seen = new Set(); const queue = [pagePath('home', 'de'), pagePath('home', 'en')]; while (queue.length > 0) { const path = queue.shift() as string; if (seen.has(path)) { continue; } seen.add(path); await page.goto(path); const urls = await page.evaluate(() => { const values = [ ...Array.from(document.querySelectorAll('a[href]'), (node) => node.getAttribute('href')), ...Array.from(document.querySelectorAll('[src]'), (node) => node.getAttribute('src')), ]; return values.filter( (value): value is string => typeof value === 'string' && value.length > 0, ); }); for (const raw of urls) { if (raw.startsWith('mailto:') || raw.startsWith('tel:') || raw.startsWith('#')) { continue; } const resolved = new URL(raw, page.url()); if (resolved.origin !== new URL(page.url()).origin) { continue; } const next = `${resolved.pathname}${resolved.search}`; const response = await request.get(next); expect(response.status(), `${raw} from ${path}`).toBeLessThan(400); if (!seen.has(next) && !next.includes('.')) { queue.push(next); } } } for (const asset of ['/robots.txt', '/sitemap.xml', '/llms.txt', SITE_CONFIG.cvAssetPath]) { const response = await request.get(asset); expect(response.status(), asset).toBe(200); } }); });