import { execFileSync } from 'node:child_process'; import { mkdirSync, rmSync } from 'node:fs'; import path from 'node:path'; import type { AddressInfo } from 'node:net'; import { createServer, type RequestListener } from 'node:http'; const ROOT = path.resolve(import.meta.dirname, '../..'); /** * Point Prisma at a throwaway SQLite file and apply migrations to it. * Must run before anything imports `src/store/db.ts`, because PrismaClient * reads DATABASE_URL when it is constructed. */ export function prepareTestDatabase(name: string): string { const dir = path.join(ROOT, 'data'); mkdirSync(dir, { recursive: true }); const file = path.join(dir, `${name}.db`); rmSync(file, { force: true }); rmSync(`${file}-journal`, { force: true }); const url = `file:${file}`; process.env.DATABASE_URL = url; execFileSync('npx', ['prisma', 'migrate', 'deploy'], { cwd: ROOT, env: { ...process.env, DATABASE_URL: url }, stdio: 'pipe', }); return url; } export interface RunningServer { baseUrl: string; close: () => Promise; } export async function startServer(app: RequestListener): Promise { const server = createServer(app); await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve)); const { port } = server.address() as AddressInfo; return { baseUrl: `http://127.0.0.1:${port}`, close: () => new Promise((resolve, reject) => server.close((err) => (err ? reject(err) : resolve())), ), }; }