import assert from 'node:assert/strict'; import { spawn } from 'node:child_process'; import { access, cp, readFile } from 'node:fs/promises'; import path from 'node:path'; import test from 'node:test'; const projectRoot = path.resolve('.'); const standaloneRoot = path.join(projectRoot, '.next', 'standalone'); const port = 43217; const origin = `http://127.0.0.1:${port}`; async function waitForServer(process, getLogs) { const deadline = Date.now() + 60_000; while (Date.now() < deadline) { if (process.exitCode !== null) throw new Error('standalone server exited early'); try { const response = await fetch(origin, { signal: AbortSignal.timeout(10_000) }); if (response.ok) return; } catch {} await new Promise((resolve) => setTimeout(resolve, 150)); } throw new Error(`standalone server did not become ready\n${getLogs()}`); } test('the standalone server renders both locales and optimizes local images', async (t) => { await access(path.join(standaloneRoot, 'server.js')); await cp(path.join(projectRoot, 'public'), path.join(standaloneRoot, 'public'), { recursive: true }); await cp( path.join(projectRoot, '.next', 'static'), path.join(standaloneRoot, '.next', 'static'), { recursive: true }, ); const server = spawn(process.execPath, ['server.js'], { cwd: standaloneRoot, env: { ...process.env, HOSTNAME: '127.0.0.1', PORT: String(port) }, stdio: ['ignore', 'pipe', 'pipe'], }); let serverLogs = ''; server.stdout.on('data', (chunk) => { serverLogs += chunk; }); server.stderr.on('data', (chunk) => { serverLogs += chunk; }); t.after(() => server.kill()); await waitForServer(server, () => serverLogs); const [englishResponse, persianResponse] = await Promise.all([ fetch(`${origin}/`), fetch(`${origin}/fa`), ]); assert.equal(englishResponse.status, 200); assert.equal(persianResponse.status, 200); const [englishHtml, persianHtml] = await Promise.all([ englishResponse.text(), persianResponse.text(), ]); assert.match(englishHtml, /]*lang="en"[^>]*dir="ltr"/i); assert.match(englishHtml, /href="\/fa"/i); assert.match(englishHtml, /hreflang="fa"/i); assert.match(englishHtml, />Software Engineer]*lang="fa"[^>]*dir="rtl"/i); assert.match(persianHtml, /سلام، من امیرحسین خلیلی هستم/); const staticAsset = englishHtml.match(/(?:src|href)="(\/_next\/static\/[^"?#]+)/)?.[1]; assert.ok(staticAsset, 'expected a built static asset'); assert.equal((await fetch(`${origin}${staticAsset}`)).status, 200); const optimized = await fetch( `${origin}/_next/image?url=%2Fimages%2Favatar.png&w=256&q=75`, { headers: { Accept: 'image/webp' } }, ); assert.equal(optimized.status, 200); assert.equal(optimized.headers.get('content-type'), 'image/webp'); assert.match(optimized.headers.get('cache-control') ?? '', /max-age=/); }); test('Persian source copy uses standard characters and punctuation', async () => { const localizedFiles = [ 'src/i18n/content.ts', 'src/data/projects.ts', 'src/data/experience.ts', 'src/data/education.ts', 'src/data/milestones.ts', ]; const source = ( await Promise.all(localizedFiles.map((file) => readFile(file, 'utf8'))) ).join('\n'); assert.doesNotMatch(source, /[يك]/, 'use Persian ی and ک instead of Arabic forms'); assert.doesNotMatch(source, /[—–]/, 'use Persian punctuation instead of em/en dashes'); });