Files
flyer-crawler.projectium.com/src/tests/setup/integration-global-setup.ts
Torben Sorensen 1d0bd630b2
Some checks failed
Deploy to Web Server flyer-crawler.projectium.com / deploy (push) Failing after 48s
test, more id fixes, and naming all files
2025-11-25 05:59:56 -08:00

107 lines
4.2 KiB
TypeScript

// src/tests/setup/integration-global-setup.ts
import { exec, ChildProcess } from 'child_process';
import { logger } from '../../services/logger';
import { getPool } from '../../services/db/connection'; // Import getPool
import { execSync } from 'child_process';
let serverProcess: ChildProcess;
export async function setup() {
console.log(`\n--- [PID:${process.pid}] Running Integration Test GLOBAL Setup ---`);
// The integration setup is now the single source of truth for preparing the test DB.
// It runs the same seed script that `npm run db:reset:test` used.
try {
console.log(`\n[PID:${process.pid}] Running database seed script...`);
execSync('npm run db:reset:test', { stdio: 'inherit' });
console.log(`✅ [PID:${process.pid}] Database seed script finished.`);
} catch (error) {
console.error('🔴 Failed to reset and seed the test database. Aborting tests.', error);
process.exit(1);
}
console.log(`\n[PID:${process.pid}] Starting backend server as a separate process...`);
// Use the dedicated test server script, which correctly uses the .env.test file.
serverProcess = exec('npm run start:test');
// --- NEW LOGGING START ---
// Listen for premature exit to debug crashes immediately
serverProcess.on('exit', (code, signal) => {
if (code !== 0 && signal !== 'SIGTERM') {
console.error(`\n[SERVER EXIT]: Backend server process exited prematurely with code ${code} and signal ${signal}`);
console.error('Check [SERVER STDERR] logs above for details.\n');
}
});
// --- NEW LOGGING END ---
serverProcess.stdout?.on('data', (data) => {
console.log(`[SERVER STDOUT]: ${data}`);
});
serverProcess.stderr?.on('data', (data) => {
console.error(`[SERVER STDERR]: ${data}`);
});
/**
* A local ping function that respects the VITE_API_BASE_URL from the test environment.
* This is necessary because the global apiClient's URL is configured for browser use.
*/
const pingTestBackend = async (): Promise<boolean> => {
const apiUrl = process.env.VITE_API_BASE_URL || 'http://localhost:3001/api';
try {
const response = await fetch(`${apiUrl.replace('/api', '')}/api/health/ping`);
if (!response.ok) return false;
const text = await response.text();
return text === 'pong';
} catch (e) {
logger.debug('Ping failed while waiting for server, this is expected.', { error: e });
return false;
}
};
const maxRetries = 10;
const retryDelay = 1000;
for (let i = 0; i < maxRetries; i++) {
try {
// If the process has already died, stop waiting
if (serverProcess.exitCode !== null) {
throw new Error(`Server process exited with code ${serverProcess.exitCode}`);
}
if (await pingTestBackend().catch(() => false)) {
console.log('✅ Backend server is running and responsive.');
return;
}
} catch (e) {
// Only log debug if we are still waiting, otherwise throw
if (serverProcess.exitCode !== null) throw e;
logger.debug('Ping failed while waiting for server, this is expected.', { error: e });
}
console.log(`[PID:${process.pid}] Waiting for backend server... (attempt ${i + 1}/${maxRetries})`);
await new Promise(resolve => setTimeout(resolve, retryDelay));
}
console.error('🔴 Backend server did not start in time. Integration tests will likely fail.');
serverProcess.kill();
throw new Error('Backend server failed to start.');
}
export async function teardown() {
console.log(`\n--- [PID:${process.pid}] Running Integration Test GLOBAL Teardown ---`);
// Close the database connection pool after all integration tests have run.
// This is the correct place to ensure all connections are closed gracefully.
const pool = getPool();
if (serverProcess) {
serverProcess.kill();
console.log('✅ Backend server process terminated.');
}
if (pool) {
// Check if the pool has any clients (total, idle, or waiting) before ending it.
// This is a safer, type-approved way to see if the pool was used, avoiding `any`.
if (pool.totalCount > 0 || pool.idleCount > 0 || pool.waitingCount > 0) {
await pool.end();
}
console.log('✅ Global database pool teardown complete.');
}
}