import { readFileSync, readdirSync } from "fs"; import path from "path"; import { afterAll, beforeEach, vi } from "vitest"; /** * Integration database wiring. * * - If TEST_DATABASE_URL is set, the real `lib/prisma` singleton is used unchanged, * pointed at that Postgres (e.g. the Docker instance). Migrations are applied once * by the global setup; files run serially and truncate between tests. * * - Otherwise, `lib/prisma` is mocked with a Prisma client backed by an in-process * PGlite database (Postgres compiled to WASM) — real Postgres semantics, fully * isolated per worker, no external server. Production code is never modified. */ const realDbUrl = process.env.TEST_DATABASE_URL?.trim(); if (realDbUrl) { process.env.DATABASE_URL = realDbUrl; } vi.mock("@/lib/prisma", async () => { if (process.env.TEST_DATABASE_URL?.trim()) { return await vi.importActual("@/lib/prisma"); } const { PGlite } = await import("@electric-sql/pglite"); const { PrismaPGlite } = await import("pglite-prisma-adapter"); const { PrismaClient } = await import("@prisma/client"); const db = await PGlite.create(); const migrationsDir = path.resolve(process.cwd(), "prisma", "migrations"); const dirs = readdirSync(migrationsDir) .filter((entry) => /^\d/.test(entry)) .sort(); for (const dir of dirs) { await db.exec(readFileSync(path.join(migrationsDir, dir, "migration.sql"), "utf8")); } const prisma = new PrismaClient({ adapter: new PrismaPGlite(db) }); return { prisma }; }); const { prisma } = await import("@/lib/prisma"); // Truncated in dependency order (children first) between every test for isolation. const TABLES = [ "MediaUsage", "MediaAsset", "PortfolioAsset", "PortfolioSection", "PortfolioProject", "Category", "AppConfig", ]; export async function resetDb() { const list = TABLES.map((table) => `"${table}"`).join(", "); await prisma.$executeRawUnsafe(`TRUNCATE TABLE ${list} RESTART IDENTITY CASCADE;`); } beforeEach(async () => { await resetDb(); }); afterAll(async () => { await prisma.$disconnect(); });