// __tests__/setup/testDbUtils.js const fs = require("fs"); const path = require("path"); const { Pool } = require("pg"); // Use pg directly for setup // Load .env.test variables require("dotenv").config({ path: path.resolve(__dirname, "../../.env.test") }); const poolConfig = { user: process.env.DB_USER, host: process.env.DB_HOST, database: process.env.DB_NAME, password: process.env.DB_PASSWORD, port: parseInt(process.env.DB_PORT || "5432", 10), }; const pool = new Pool(poolConfig); const initSql = fs.readFileSync( path.resolve(__dirname, "../../init.sql"), "utf8" ); async function initializeTestDB() { const client = await pool.connect(); try { // Drop all tables (order matters due to FK constraints) // This is a simple way for tests; migrations are better for complex apps. await client.query("DROP TABLE IF EXISTS user_sessions CASCADE;"); await client.query("DROP TABLE IF EXISTS api_keys CASCADE;"); await client.query("DROP TABLE IF EXISTS submissions CASCADE;"); await client.query("DROP TABLE IF EXISTS forms CASCADE;"); await client.query("DROP TABLE IF EXISTS users CASCADE;"); await client.query("DROP TABLE IF EXISTS rate_limits CASCADE;"); // If you used this table // Potentially drop extensions or other objects if init.sql creates them and they persist // Re-run init.sql // Note: node-postgres pool.query might not execute multi-statement SQL directly from a file easily. // It's often better to split init.sql or execute statements one by one. // For simplicity here, assuming init.sql can be run or you adjust this. // A common approach is to split init.sql by ';' (excluding those in strings/comments) const statements = initSql .split(";\n") .map((s) => s.trim()) .filter((s) => s.length > 0); for (const statement of statements) { if (statement.toUpperCase().startsWith("CREATE TRIGGER")) { // pg doesn't like CREATE TRIGGER in multi-statement query via client.query // Skip or handle differently if complex. For now, we assume init.sql is mostly CREATE TABLE / INSERT // Or, ensure your init.sql puts CREATE EXTENSION at the very top if needed. // console.warn("Skipping TRIGGER creation in test setup, ensure DB compatibility or handle manually."); } else { await client.query(statement); } } console.log("Test database initialized/reset."); } catch (err) { console.error("Error initializing test database:", err); throw err; } finally { client.release(); } } async function clearTable(tableName) { const client = await pool.connect(); try { await client.query(`DELETE FROM "${tableName}";`); // Or TRUNCATE if preferred and allowed } finally { client.release(); } } async function clearAllTables() { const client = await pool.connect(); try { await client.query("DELETE FROM user_sessions;"); await client.query("DELETE FROM api_keys;"); await client.query("DELETE FROM submissions;"); await client.query("DELETE FROM forms;"); await client.query("DELETE FROM users;"); await client.query("DELETE FROM rate_limits;"); } finally { client.release(); } } async function disconnectTestDB() { await pool.end(); console.log("Test database pool disconnected."); } module.exports = { pool, // Export the pool for direct use in tests if needed initializeTestDB, clearTable, clearAllTables, disconnectTestDB, };