Some checks failed
Deploy to Web Server flyer-crawler.projectium.com / deploy (push) Failing after 48s
107 lines
4.2 KiB
TypeScript
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.');
|
|
}
|
|
} |