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', ]; const VIEWPORTS = [320, 768, 1024, 1440] as const; test.describe('layout and crawlability', () => { test('does not overflow horizontally on checked routes', async ({ page }) => { for (const width of VIEWPORTS) { await page.setViewportSize({ width, height: 900 }); for (const path of CHECKED) { await page.goto(path); await expectNoOverflow(page, path, width); } } }); 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, baseURI } = 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 { baseURI: document.baseURI, urls: 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, baseURI); if (resolved.origin !== new URL(baseURI).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); } }); });