import { execSync } from 'node:child_process'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import pg from 'pg'; import { drizzle } from 'drizzle-orm/node-postgres'; import { migrate } from 'drizzle-orm/node-postgres/migrator'; import { E2E_CONTAINER, E2E_DATABASE_URL, E2E_DB_NAME, E2E_DB_PASSWORD, E2E_DB_PORT, } from './env'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const MIGRATIONS = path.resolve(__dirname, '../../../packages/db/migrations'); async function waitForPostgres(timeoutMs = 60_000): Promise { const deadline = Date.now() + timeoutMs; let lastErr: unknown; while (Date.now() < deadline) { const client = new pg.Client({ connectionString: E2E_DATABASE_URL }); try { await client.connect(); await client.query('select 1'); await client.end(); return; } catch (err) { lastErr = err; await client.end().catch(() => {}); await new Promise((r) => setTimeout(r, 500)); } } throw new Error(`e2e postgres did not become ready in ${timeoutMs}ms: ${lastErr}`); } export default async function setup() { try { execSync(`docker rm -f ${E2E_CONTAINER}`, { stdio: 'ignore' }); } catch { // no stale container — fine } execSync( `docker run --rm -d --name ${E2E_CONTAINER} -p ${E2E_DB_PORT}:5432 ` + `-e POSTGRES_PASSWORD=${E2E_DB_PASSWORD} -e POSTGRES_DB=${E2E_DB_NAME} postgres:16-alpine`, { stdio: 'inherit' }, ); try { await waitForPostgres(); const pool = new pg.Pool({ connectionString: E2E_DATABASE_URL, max: 2 }); try { await migrate(drizzle(pool), { migrationsFolder: MIGRATIONS }); } finally { await pool.end(); } } catch (err) { execSync(`docker rm -f ${E2E_CONTAINER}`, { stdio: 'ignore' }); throw err; } return () => { execSync(`docker rm -f ${E2E_CONTAINER}`, { stdio: 'ignore' }); }; }