85 lines
3.2 KiB
TypeScript
85 lines
3.2 KiB
TypeScript
import { execSync } from "node:child_process";
|
|
import { readFileSync, existsSync } from "node:fs";
|
|
import { resolve } from "node:path";
|
|
import { beforeAll, afterAll } from "vitest";
|
|
import { PrismaClient } from "@prisma/client";
|
|
|
|
function readEnvValue(filePath: string, key: string): string | undefined {
|
|
if (!existsSync(filePath)) return undefined;
|
|
const content = readFileSync(filePath, "utf8");
|
|
const line = content
|
|
.split(/\r?\n/)
|
|
.find((raw) => raw.trim().startsWith(`${key}=`));
|
|
if (!line) return undefined;
|
|
const value = line.slice(line.indexOf("=") + 1).trim();
|
|
return value.length > 0 ? value : undefined;
|
|
}
|
|
|
|
function resolveDatabaseUrl(): string {
|
|
if (process.env.TEST_DATABASE_URL?.trim()) return process.env.TEST_DATABASE_URL.trim();
|
|
if (process.env.BACKUP_DATABASE_URL?.trim()) return process.env.BACKUP_DATABASE_URL.trim();
|
|
if (process.env.DATABASE_URL?.trim()) return process.env.DATABASE_URL.trim();
|
|
|
|
const envPaths = [resolve(process.cwd(), ".env"), resolve(process.cwd(), "..", ".env")];
|
|
for (const envPath of envPaths) {
|
|
const testUrl = readEnvValue(envPath, "TEST_DATABASE_URL");
|
|
if (testUrl) return testUrl;
|
|
const backupUrl = readEnvValue(envPath, "BACKUP_DATABASE_URL");
|
|
if (backupUrl) return backupUrl;
|
|
const dbUrl = readEnvValue(envPath, "DATABASE_URL");
|
|
if (dbUrl) return dbUrl.replace("@postgres:", "@127.0.0.1:");
|
|
}
|
|
|
|
return "postgres://app:app@127.0.0.1:5432/skymoney";
|
|
}
|
|
|
|
process.env.NODE_ENV = process.env.NODE_ENV || "test";
|
|
process.env.DATABASE_URL = resolveDatabaseUrl();
|
|
process.env.PORT = process.env.PORT || "8081";
|
|
process.env.HOST ??= "127.0.0.1";
|
|
process.env.CORS_ORIGIN = process.env.CORS_ORIGIN || "";
|
|
process.env.AUTH_DISABLED = process.env.AUTH_DISABLED || "1";
|
|
process.env.SEED_DEFAULT_BUDGET = process.env.SEED_DEFAULT_BUDGET || "1";
|
|
process.env.JWT_SECRET =
|
|
process.env.JWT_SECRET || "test-jwt-secret-32-chars-min-abcdef";
|
|
process.env.COOKIE_SECRET =
|
|
process.env.COOKIE_SECRET || "test-cookie-secret-32-chars-abcdef";
|
|
|
|
export const prisma = new PrismaClient();
|
|
|
|
// hard reset for a single user
|
|
export async function resetUser(userId: string) {
|
|
await prisma.allocation.deleteMany({ where: { userId } });
|
|
await prisma.transaction.deleteMany({ where: { userId } });
|
|
await prisma.incomeEvent.deleteMany({ where: { userId } });
|
|
await prisma.fixedPlan.deleteMany({ where: { userId } });
|
|
await prisma.variableCategory.deleteMany({ where: { userId } });
|
|
await prisma.user.deleteMany({ where: { id: userId } });
|
|
}
|
|
|
|
beforeAll(async () => {
|
|
// Optional schema bootstrap for CI/local environments that can run Prisma CLI.
|
|
if (process.env.TEST_APPLY_SCHEMA === "1") {
|
|
try {
|
|
execSync("npx prisma migrate deploy", { stdio: "inherit" });
|
|
} catch {
|
|
execSync("npx prisma db push --skip-generate --accept-data-loss", { stdio: "inherit" });
|
|
}
|
|
}
|
|
|
|
// Ensure a clean slate: wipe all tables to avoid cross-file leakage
|
|
await prisma.$transaction([
|
|
prisma.emailToken.deleteMany({}),
|
|
prisma.allocation.deleteMany({}),
|
|
prisma.transaction.deleteMany({}),
|
|
prisma.incomeEvent.deleteMany({}),
|
|
prisma.fixedPlan.deleteMany({}),
|
|
prisma.variableCategory.deleteMany({}),
|
|
prisma.user.deleteMany({}),
|
|
]);
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await prisma.$disconnect();
|
|
});
|