import assert from 'node:assert/strict'; import { spawn, spawnSync } from 'node:child_process'; import { access, cp, readFile, mkdtemp, rm } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import { once } from 'node:events'; 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 generic samples without private content', async (t) => { const dataDir = await mkdtemp(path.join(tmpdir(), 'portfolio-runtime-')); const env = { ...process.env, DATA_DIR: dataDir, SITE_URL: origin, HOSTNAME: '127.0.0.1', PORT: String(port) }; 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 imported = spawnSync(process.execPath, ['maintenance.mjs', 'init'], { cwd: standaloneRoot, env, encoding: 'utf8' }); assert.equal(imported.status, 0, imported.stderr); const server = spawn(process.execPath, ['server.js'], { cwd: standaloneRoot, env, stdio: ['ignore', 'pipe', 'pipe'], }); let serverLogs = ''; server.stdout.on('data', (chunk) => { serverLogs += chunk; }); server.stderr.on('data', (chunk) => { serverLogs += chunk; }); t.after(async () => { if (server.exitCode === null) { const exited = once(server, 'exit'); server.kill(); await exited; } await rm(dataDir, { recursive: true, force: true }); }); await waitForServer(server, () => serverLogs); const englishResponse = await fetch(`${origin}/`); assert.equal(englishResponse.status, 200); const englishHtml = await englishResponse.text(); assert.match(englishHtml, /]*lang="en"[^>]*dir="ltr"/i); assert.match(englishHtml, /Your Name/); assert.equal((await fetch(`${origin}/fa`)).status, 404); assert.equal((await fetch(`${origin}/projects/sample-projects`)).status, 200); assert.equal((await fetch(`${origin}/projects/not-a-project`)).status, 404); 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 placeholder = await fetch(`${origin}/images/portfolio-placeholder.svg`); assert.equal(placeholder.status, 200); });