/** * Build-output test for BaseLayout.astro * Runs after `npm run build` and checks the dist HTML for expected structure. */ import { readFileSync, existsSync } from 'fs'; import { resolve } from 'path'; const distDir = resolve('dist'); const indexPath = resolve(distDir, 'index.html'); let failures = 0; let passes = 0; function assert(condition, label) { if (condition) { console.log(` ✓ ${label}`); passes++; } else { console.error(` ✗ FAIL: ${label}`); failures++; } } // ── Source file existence checks ── console.log('\n--- Source file checks ---'); assert( existsSync(resolve('src/layouts/BaseLayout.astro')), 'src/layouts/BaseLayout.astro exists' ); assert( existsSync(resolve('src/pages/index.astro')), 'src/pages/index.astro exists' ); // ── Source content checks ── console.log('\n--- Source content checks ---'); if (existsSync(resolve('src/layouts/BaseLayout.astro'))) { const layoutSrc = readFileSync(resolve('src/layouts/BaseLayout.astro'), 'utf-8'); assert( layoutSrc.includes("import '../styles/tokens.css'") || layoutSrc.includes("import '../styles/tokens.css';"), 'BaseLayout imports tokens.css' ); assert( layoutSrc.includes("import '../styles/fonts.css'") || layoutSrc.includes("import '../styles/fonts.css';"), 'BaseLayout imports fonts.css' ); assert( /title:\s*string/.test(layoutSrc), 'Props interface has title: string' ); assert( /description\?:\s*string/.test(layoutSrc), 'Props interface has description?: string' ); assert( layoutSrc.includes('skip-link'), 'BaseLayout has skip-link class' ); assert( layoutSrc.includes("skip-to-content") || layoutSrc.includes("Skip to content"), 'BaseLayout has skip-to-content link text' ); assert( layoutSrc.includes('') || layoutSrc.includes(""), 'BaseLayout has named nav slot' ); assert( layoutSrc.includes('id="main-content"') || layoutSrc.includes("id='main-content'"), 'BaseLayout has main with id=main-content' ); assert( layoutSrc.includes('Crash Test Dev'), 'BaseLayout references site name for title computation' ); assert( layoutSrc.includes('import.meta.env.BASE_URL'), 'BaseLayout reads import.meta.env.BASE_URL' ); } if (existsSync(resolve('src/pages/index.astro'))) { const indexSrc = readFileSync(resolve('src/pages/index.astro'), 'utf-8'); assert( indexSrc.includes('BaseLayout'), 'index.astro uses BaseLayout' ); } // ── Build output checks ── console.log('\n--- Build output checks ---'); assert(existsSync(indexPath), 'dist/index.html exists'); if (existsSync(indexPath)) { const html = readFileSync(indexPath, 'utf-8'); assert(html.includes('') || html.includes(''), 'Has doctype'); assert(html.includes('lang="en"') || html.includes("lang='en'"), 'html has lang=en'); assert(html.includes('charset'), 'Has charset meta'); assert(html.includes('viewport'), 'Has viewport meta'); // Astro extracts CSS into separate files; check both HTML and linked CSS bundles const { readdirSync } = await import('fs'); const astroDir = resolve(distDir, '_astro'); let distCss = ''; if (existsSync(astroDir)) { for (const f of readdirSync(astroDir)) { if (f.endsWith('.css')) { distCss += readFileSync(resolve(astroDir, f), 'utf-8'); } } } assert( html.includes('Source Serif') || distCss.includes('Source Serif'), 'dist output (HTML or CSS) contains Source Serif reference' ); assert(html.includes('skip-link') || html.includes('Skip to content'), 'Has skip link'); assert(html.includes('main-content'), 'Has main-content id'); assert( html.includes('Crash Test Dev'), 'Title contains Crash Test Dev' ); assert( html.includes('application/rss+xml') || html.includes('rss'), 'Has RSS link' ); } // ── Summary ── console.log(`\n--- Results: ${passes} passed, ${failures} failed ---`); if (failures > 0) { process.exit(1); }