// test/helpers/deno-server.js import { spawn } from 'node:child_process'; import { mkdirSync, rmSync } from 'node:fs'; import { TEST_PORT } from './test-port.js'; const TEST_DATA_DIR = './test-data'; const USE_LOCAL_INFRA = process.env.USE_LOCAL_INFRA !== 'false'; /** @type {import('node:child_process').ChildProcess | null} */ let denoProcess = null; /** * Start Deno PDS server for e2e tests * Spawns Deno process running examples/deno/main.ts * @returns {Promise<{close: () => Promise}>} Server instance with close() method */ export async function startDenoServer() { // Fresh data each run rmSync(TEST_DATA_DIR, { recursive: true, force: true }); mkdirSync(TEST_DATA_DIR, { recursive: true }); const hostname = USE_LOCAL_INFRA ? 'host.docker.internal:3443' : `localhost:${TEST_PORT}`; const env = { ...process.env, PDS_DB_PATH: `${TEST_DATA_DIR}/pds.db`, PDS_BLOBS_DIR: `${TEST_DATA_DIR}/blobs`, JWT_SECRET: 'test-secret-for-e2e', HOSTNAME: hostname, PORT: String(TEST_PORT), PDS_PASSWORD: 'test-password', RELAY_URL: USE_LOCAL_INFRA ? 'http://localhost:2470' : '', APPVIEW_URL: 'https://api.bsky.app', APPVIEW_DID: 'did:web:api.bsky.app', }; denoProcess = spawn( 'deno', [ 'run', '--allow-net', '--allow-read', '--allow-write', '--allow-env', '--unstable-ffi', 'examples/deno/main.ts', ], { env, stdio: ['ignore', 'pipe', 'pipe'], cwd: process.cwd(), }, ); // Log output for debugging denoProcess.stdout?.on('data', (data) => { const msg = data.toString().trim(); if (msg) console.log(`[deno] ${msg}`); }); denoProcess.stderr?.on('data', (data) => { const msg = data.toString().trim(); if (msg) console.error(`[deno] ${msg}`); }); // Wait for server to be ready await waitForReady(); return { async close() { if (denoProcess) { denoProcess.kill('SIGTERM'); // Wait for process to exit await new Promise((resolve) => { denoProcess?.on('exit', resolve); // Timeout after 5s setTimeout(resolve, 5000); }); denoProcess = null; } }, }; } /** * Wait for Deno server to be ready */ async function waitForReady(maxAttempts = 30) { for (let i = 0; i < maxAttempts; i++) { try { const res = await fetch(`http://localhost:${TEST_PORT}/`); if (res.ok) return; } catch { // Server not ready yet } await new Promise((r) => setTimeout(r, 500)); } throw new Error('Deno server failed to start'); } /** * Stop Deno PDS server * @param {{close: () => Promise}} server - Server instance from startDenoServer */ export async function stopDenoServer(server) { await server.close(); } export { TEST_PORT, USE_LOCAL_INFRA };