- Next.js 14 (TS, App Router) monolith - Request entity (Draft state) via Prisma + Postgres, validated with Zod - ESLint configured - Tailwind v4 + shadcn/ui (new-york-v4 style) - Vitest test suite (6 tests, runs against throwaway Postgres DB per file) - Multi-agent dev workflow docs in CLAUDE.md and .claude/agents/
64 lines
2.4 KiB
TypeScript
64 lines
2.4 KiB
TypeScript
// Creates a throwaway Postgres database per test-file run against the
|
|
// docker-compose `db` service, points DATABASE_URL at it so tests never
|
|
// touch a shared dev database, and drops it afterwards. Mirrors the old
|
|
// sqlite temp-file-per-run isolation, adapted to Postgres (CREATE/DROP
|
|
// DATABASE instead of a throwaway file).
|
|
//
|
|
// Creating/dropping the throwaway database itself stays raw `pg` (test
|
|
// infra, not the app's data-access layer) — but applying the schema to the
|
|
// fresh database, and tearing down the pooled connection afterwards, now
|
|
// goes through Prisma instead of the old db.ts.
|
|
import { randomUUID } from "node:crypto";
|
|
import { execSync } from "node:child_process";
|
|
import { Client } from "pg";
|
|
import { afterAll, beforeAll } from "vitest";
|
|
import { prisma } from "@/lib/prisma";
|
|
|
|
const baseUrl = new URL(
|
|
process.env.DATABASE_URL ||
|
|
"postgres://asset_license_mgmt:change-me-local-dev@db:5432/asset_license_mgmt"
|
|
);
|
|
const testDbName = `test_${randomUUID().replace(/-/g, "_")}`;
|
|
|
|
function adminUrl(): string {
|
|
const url = new URL(baseUrl.toString());
|
|
url.pathname = "/postgres";
|
|
return url.toString();
|
|
}
|
|
|
|
async function withAdminClient<T>(fn: (client: Client) => Promise<T>): Promise<T> {
|
|
const client = new Client({ connectionString: adminUrl() });
|
|
await client.connect();
|
|
try {
|
|
return await fn(client);
|
|
} finally {
|
|
await client.end();
|
|
}
|
|
}
|
|
|
|
beforeAll(async () => {
|
|
await withAdminClient((client) => client.query(`CREATE DATABASE ${testDbName}`));
|
|
|
|
const testUrl = new URL(baseUrl.toString());
|
|
testUrl.pathname = `/${testDbName}`;
|
|
process.env.DATABASE_URL = testUrl.toString();
|
|
|
|
// Apply the Prisma migration history to the fresh throwaway database.
|
|
// `migrate deploy` replays the same real migrations production uses
|
|
// (prisma/migrations), rather than a schema-diffing shortcut like
|
|
// `db push` — keeping this test setup honest about what actually runs
|
|
// outside tests too.
|
|
execSync("npx prisma migrate deploy", { stdio: "inherit" });
|
|
}, 30_000);
|
|
|
|
afterAll(async () => {
|
|
// Disconnect the app's Prisma Client singleton first so the admin
|
|
// connection is free to drop the database (DROP DATABASE ... WITH
|
|
// (FORCE) would also disconnect it, but closing cleanly first avoids
|
|
// relying on that).
|
|
await prisma.$disconnect();
|
|
await withAdminClient((client) =>
|
|
client.query(`DROP DATABASE IF EXISTS ${testDbName} WITH (FORCE)`)
|
|
);
|
|
});
|