import { expect, test } from '@playwright/test'; import { canonicalSiteUrl, docsRoutes, expectCoreCapabilitiesVisible, expectMetadataForRoute, expectNoForbiddenPublicClaims, expectNoHorizontalOverflow, expectNoPlaceholderLinks, expectPublicLinksAreIntentional, expectSitemapExcludesRoutes, expectSitemapIncludesRoutes, readSitemapUrls, redirectRouteExpectations, redirectRoutes, renderedRoutes, } from './smoke-helpers'; import { readFile } from 'node:fs/promises'; import { globby } from 'globby'; const routeMetadata = { '/': { title: /Tenantial.*Evidenzbasierte Microsoft-Tenant-Governance/i, description: /evidenzbasierte Governance/i, }, '/platform': { title: /Plattform \| Tenantial/i, description: /öffentliches Produktmodell/i, }, '/pricing': { title: /Preise \| Tenantial/i, description: /Evaluierungs.*Rollout/i, }, '/contact': { title: /Kontakt \| Tenantial/i, description: /Walkthrough.*Rollout/i, }, '/trust': { title: /Vertrauen \| Tenantial/i, description: /Trust-Posture.*statische.*Previews/i, }, '/legal': { title: /Rechtliches \| Tenantial/i, description: /rechtliche Website-Informationen/i, }, '/privacy': { title: /Datenschutz \| Tenantial/i, description: /Website-Datenschutzhinweis/i, }, '/terms': { title: /Nutzungsbedingungen \| Tenantial/i, description: /Website-Nutzungsbedingungen/i, }, '/imprint': { title: /Impressum \| Tenantial/i, description: /Veröffentlichungsinformationen/i, }, '/welcome-to-docs/': { title: /Tenantial Docs/i, description: /Microsoft-Tenant-Governance-Modell/i, }, '/guides/intro/': { title: /Einführung in Tenantial/i, description: /Microsoft-Tenant-Governance-Modell/i, }, '/guides/getting-started/': { title: /Getting Started/i, description: /Tenantial Walkthrough/i, }, '/guides/first-project-checklist/': { title: /Evaluierungscheckliste/i, description: /frühe Tenantial-Evaluierung/i, }, '/platform/evidence-review/': { title: /Evidence Review/i, description: /Evidence-Review-Workflows/i, }, '/en/': { title: /Tenantial.*Evidence-first Microsoft tenant governance/i, description: /evidence-first governance for Microsoft tenant configuration/i, }, '/en/platform': { title: /Platform \| Tenantial/i, description: /public product model for Microsoft tenant/i, }, '/en/pricing': { title: /Pricing \| Tenantial/i, description: /evaluation and rollout conversation paths/i, }, '/en/contact': { title: /Contact \| Tenantial/i, description: /walkthrough.*scoped rollout conversation/i, }, '/en/trust': { title: /Trust \| Tenantial/i, description: /conservative claims.*static preview boundaries/i, }, '/en/legal': { title: /Legal \| Tenantial/i, description: /public website legal information/i, }, '/en/privacy': { title: /Privacy \| Tenantial/i, description: /public website privacy notice/i, }, '/en/terms': { title: /Terms \| Tenantial/i, description: /public website terms/i, }, '/en/imprint': { title: /Imprint \| Tenantial/i, description: /public website publication information/i, }, '/en/welcome-to-docs/': { title: /Tenantial Docs/i, description: /evidence-first Microsoft tenant governance model/i, }, '/en/guides/intro/': { title: /Introduction to Tenantial/i, description: /evidence-first Microsoft tenant governance model/i, }, '/en/guides/getting-started/': { title: /Getting Started/i, description: /Tenantial walkthrough/i, }, '/en/guides/first-project-checklist/': { title: /Evaluation Checklist/i, description: /conservative checklist for early Tenantial evaluation/i, }, '/en/platform/evidence-review/': { title: /Evidence Review/i, description: /Tenantial evidence review workflows/i, }, } as const; for (const route of renderedRoutes) { test(`renders intentional route ${route}`, async ({ page }) => { await page.goto(route); await expect(page.locator('body')).toContainText('Tenantial'); await expectNoForbiddenPublicClaims(page); await expectNoHorizontalOverflow(page); }); } test('homepage first viewport explains core Tenantial capabilities', async ({ page, }) => { await page.goto('/'); const heading = page.getByRole('heading', { name: /Evidenzbasierte Governance für Microsoft-Tenant-Konfiguration/i, }); await expect(heading).toBeVisible(); const box = await heading.boundingBox(); expect(box?.y ?? Number.POSITIVE_INFINITY).toBeLessThan(420); await expect( page.getByRole('link', { name: /Walkthrough anfragen/i }).first() ).toHaveAttribute('href', '/contact'); await expect( page.getByRole('link', { name: /Plattform ansehen/i }).first() ).toHaveAttribute('href', '/platform'); await expectCoreCapabilitiesVisible(page); }); test('/platform explains the public product model without internal runtime terms', async ({ page, }) => { await page.goto('/platform'); await expect( page.getByRole('heading', { name: /Plattform-Review-Modell/i }) ).toBeVisible(); await expectCoreCapabilitiesVisible(page); await expect(page.locator('body')).toContainText(/statische Demo-Previews/i); await expect(page.locator('body')).toContainText( /authentifiziert keine Besucher, liest keinen Microsoft Tenant, führt keine Operationen aus und speichert keine Tenant-Exporte/i ); const text = await page.locator('body').innerText(); expect(text).not.toMatch(/\b(Laravel|Filament|Livewire)\b/i); expect(text).not.toMatch(/\bGraph runtime\b/i); }); for (const route of renderedRoutes) { test(`public links on ${route} resolve intentionally`, async ({ page, request, }) => { await page.goto(route); await expectNoPlaceholderLinks(page); await expectPublicLinksAreIntentional(page, request, route); }); } test('built HTML emits no placeholder href values', async () => { const htmlFiles = await globby('dist/**/*.html', { absolute: true, cwd: process.cwd(), }); expect(htmlFiles.length).toBeGreaterThan(0); for (const file of htmlFiles) { const html = await readFile(file, 'utf8'); expect(html, file).not.toMatch(/href=(["'])#\1/); expect(html, file).not.toMatch(/href=\{["']#["']\}/); } }); for (const route of [ '/trust', '/pricing', '/legal', '/privacy', '/terms', '/imprint', ...docsRoutes, ] as const) { test(`claim-sensitive route ${route} stays conservative`, async ({ page, }) => { await page.goto(route); await expectNoForbiddenPublicClaims(page); await expectNoHorizontalOverflow(page); }); } for (const [route, expected] of Object.entries(routeMetadata)) { test(`metadata is route-specific for ${route}`, async ({ page }) => { await page.goto(route); await expectMetadataForRoute(page, route, expected); }); } for (const route of redirectRoutes) { test(`redirects ${route} intentionally`, async ({ page, request }) => { const response = await request.get(route, { maxRedirects: 0 }); const expected = redirectRouteExpectations[route]; if (response.status() >= 300 && response.status() < 400) { expect(response.status()).toBe(expected.status); expect(response.headers().location).toBe(expected.target); } else { expect(response.status()).toBe(200); const html = await response.text(); expect(html).toContain('name="robots" content="noindex"'); expect(html).toContain( `rel="canonical" href="${canonicalSiteUrl}${expected.target}"` ); expect(html).toContain(`href="${expected.target}"`); } await page.goto(route); await expect(page).toHaveURL(new RegExp(`${expected.target}/?$`)); await expect( page.getByRole('heading', { name: /Plattform-Review-Modell|Platform review model/, }) ).toBeVisible(); }); } test('robots and sitemap are available', async ({ page }) => { await page.goto('/robots.txt'); await expect(page.locator('body')).toContainText( `Sitemap: ${canonicalSiteUrl}/sitemap-index.xml` ); await page.goto('/sitemap-index.xml'); await expect(page.locator('body')).toContainText('sitemap-0.xml'); }); test('sitemap exposes canonical routes and excludes redirect aliases', async ({ page, }) => { const sitemapUrls = await readSitemapUrls(page); expectSitemapIncludesRoutes(sitemapUrls, renderedRoutes); expectSitemapExcludesRoutes(sitemapUrls, redirectRoutes); });