import { describe, it } from 'node:test'; import { strict as assert } from 'node:assert'; import { readFileSync, existsSync } from 'node:fs'; import { resolve } from 'node:path'; const pagePath = resolve('src/pages/index.astro'); function readPage() { return readFileSync(pagePath, 'utf-8'); } describe('Index page', () => { it('should exist at src/pages/index.astro', () => { assert.ok(existsSync(pagePath), 'Index page file should exist'); }); describe('Imports', () => { it('should import getCollection from astro:content', () => { const content = readPage(); assert.match(content, /import\s+.*getCollection.*from\s+['"]astro:content['"]/, 'should import getCollection'); }); it('should import BaseLayout', () => { const content = readPage(); assert.match(content, /import\s+BaseLayout\s+from\s+['"].*BaseLayout\.astro['"]/, 'should import BaseLayout'); }); it('should import NavBar', () => { const content = readPage(); assert.match(content, /import\s+NavBar\s+from\s+['"].*NavBar\.astro['"]/, 'should import NavBar'); }); it('should import getReadingTime', () => { const content = readPage(); assert.match(content, /import\s+.*getReadingTime.*from\s+['"].*reading-time['"]/, 'should import getReadingTime'); }); }); describe('Data fetching', () => { it('should fetch all posts with getCollection', () => { const content = readPage(); assert.match(content, /getCollection\s*\(\s*['"]posts['"]\s*\)/, 'should call getCollection("posts")'); }); }); describe('Hero section', () => { it('should have a hero section', () => { const content = readPage(); assert.match(content, /class="hero"/, 'should have a section with class hero'); }); it('should have the site title Crash Test Dev as a heading', () => { const content = readPage(); assert.match(content, /]*>Crash Test Dev<\/h1>/, 'should have h1 with site title'); }); it('should have a tagline in prose font', () => { const content = readPage(); assert.match(content, /class="tagline"/, 'should have a tagline element'); }); it('should have an author byline', () => { const content = readPage(); assert.match(content, /class="byline"/, 'should have a byline element'); }); it('should contain an inline SVG hero illustration', () => { const content = readPage(); // The hero section should contain an SVG element assert.match(content, /class="hero-illustration"/, 'should have a hero illustration'); assert.match(content, /]*viewBox/, 'should have an inline SVG with viewBox'); }); it('should use CSS grid for hero layout', () => { const content = readPage(); assert.match(content, /\.hero\s*\{[^}]*display:\s*grid/s, 'hero should use CSS grid'); assert.match(content, /\.hero\s*\{[^}]*grid-template-columns/s, 'hero should define grid-template-columns'); }); it('should be full viewport width', () => { const content = readPage(); assert.match(content, /\.hero\s*\{[^}]*max-width:\s*100%/s, 'hero should be full viewport width'); }); }); describe('Featured excerpt section', () => { it('should have a featured excerpt section', () => { const content = readPage(); assert.match(content, /class="featured"/, 'should have a section with class featured'); }); it('should contain an excerpt blockquote', () => { const content = readPage(); assert.match(content, /]*class="excerpt"/, 'should have a blockquote with class excerpt'); }); it('should have a link to the full post', () => { const content = readPage(); assert.match(content, /class="featured-link"/, 'should have a featured-link to the full post'); }); it('should have a terracotta left border on the featured section', () => { const content = readPage(); assert.match(content, /\.featured[\s\S]*?border-left.*accent-primary/s, 'should have terracotta left border'); }); it('should include an inline SVG diagram from a post', () => { const content = readPage(); // The featured section should contain a small SVG from one of the posts assert.match(content, /class="featured-diagram"/, 'should have a featured-diagram element'); }); }); describe('Series section - multi-column grid', () => { it('should have a series section', () => { const content = readPage(); assert.match(content, /class="series"/, 'should have a section with class series'); }); it('should mention the Rage series', () => { const content = readPage(); assert.match(content, /Rage/, 'should mention Rage in the series section'); }); it('should use a CSS grid for series cards', () => { const content = readPage(); assert.match(content, /\.series-grid\s*\{[^}]*display:\s*grid/s, 'should use CSS grid for series cards'); assert.match(content, /\.series-grid\s*\{[^}]*grid-template-columns:\s*1fr\s+1fr/s, 'should have 2-column grid'); }); it('should have series card elements', () => { const content = readPage(); assert.match(content, /series-card/, 'should have series-card elements'); }); it('should show card numbers in mono font with accent color', () => { const content = readPage(); assert.match(content, /class="card-number"/, 'should have card-number elements'); assert.match(content, /\.card-number\s*\{[^}]*font-family:\s*var\(--font-evidence\)/s, 'card number should use mono font'); assert.match(content, /\.card-number\s*\{[^}]*color:\s*var\(--accent-primary\)/s, 'card number should use accent color'); }); it('should show card descriptions', () => { const content = readPage(); assert.match(content, /class="card-description"/, 'should have card-description elements'); }); it('should indicate coming soon items', () => { const content = readPage(); assert.match(content, /coming soon/i, 'should indicate coming soon posts'); }); it('should use --width-container for series section width', () => { const content = readPage(); assert.match(content, /\.series\s*\{[^}]*max-width:\s*var\(--width-container\)/s, 'series should use container width'); }); it('should collapse to single column on mobile', () => { const content = readPage(); // Check for media query that changes grid to 1 column assert.match(content, /@media.*768px[\s\S]*?grid-template-columns:\s*1fr\s*[;}]/s, 'should collapse to 1 column on mobile'); }); it('should have card surface background', () => { const content = readPage(); assert.match(content, /\.series-card\s*\{[^}]*background[^:]*:\s*var\(--surface-card\)/s, 'cards should have card surface bg'); }); }); describe('All posts section - 2-column grid', () => { it('should have a posts listing section', () => { const content = readPage(); assert.match(content, /class="all-posts"/, 'should have a section with class all-posts'); }); it('should map posts to entries', () => { const content = readPage(); assert.match(content, /sortedPosts\.map/, 'should map sortedPosts'); }); it('should show post titles as links', () => { const content = readPage(); assert.match(content, /posts\/\$\{post\.id\}/, 'should link to post pages'); }); it('should use --width-prose for all-posts width', () => { const content = readPage(); assert.match(content, /\.all-posts\s*\{[^}]*max-width:\s*var\(--width-prose\)/s, 'all-posts should use prose width'); }); it('should use CSS grid for posts on desktop', () => { const content = readPage(); assert.match(content, /\.posts-grid\s*\{[^}]*display:\s*grid/s, 'should use CSS grid for posts'); assert.match(content, /\.posts-grid\s*\{[^}]*grid-template-columns:\s*1fr\s+1fr/s, 'should have 2-column posts grid'); }); }); describe('Layout', () => { it('should use BaseLayout with title Crash Test Dev', () => { const content = readPage(); assert.match(content, / { const content = readPage(); assert.match(content, / { it('should use --font-structure for hero heading', () => { const content = readPage(); assert.match(content, /\.hero[\s\S]*?font-family:\s*var\(--font-structure\)/, 'should use structure font in hero'); }); it('should use --font-prose for excerpt', () => { const content = readPage(); assert.match(content, /\.excerpt[\s\S]*?font-family:\s*var\(--font-prose\)/, 'should use prose font for excerpt'); }); it('should not have the old .post-list as the main layout', () => { const content = readPage(); assert.doesNotMatch(content, / { const content = readPage(); // Hero: full width (100%) assert.match(content, /\.hero[\s\S]*?max-width:\s*100%/s, 'hero should be full width'); // Series: container width assert.match(content, /\.series[\s\S]*?max-width:\s*var\(--width-container\)/s, 'series should use container width'); // All posts: prose width assert.match(content, /\.all-posts[\s\S]*?max-width:\s*var\(--width-prose\)/s, 'all-posts should use prose width'); }); }); describe('Rage series data', () => { it('should have descriptions for each series item', () => { const content = readPage(); // Check for at least a couple of the descriptions assert.match(content, /silent stale cache/i, 'should have description for post 1'); assert.match(content, /Weak fingerprints find candidates/i, 'should have description for post 2'); assert.match(content, /content-addressed storage/i, 'should have description for post 5'); }); it('should include all 6 rage series items', () => { const content = readPage(); assert.match(content, /Your Build Cache Is Lying to You/, 'should have post 1'); assert.match(content, /Two-Phase Fingerprinting/, 'should have post 2'); assert.match(content, /Hooking Syscalls/, 'should have post 3'); assert.match(content, /TypeScript 7/, 'should have post 4'); assert.match(content, /node_modules/, 'should have post 5'); assert.match(content, /Maintaining Lage/, 'should have post 6'); }); }); });