tests cannot connect to db
Some checks failed
Deploy to Web Server flyer-crawler.projectium.com / deploy (push) Failing after 1m3s

This commit is contained in:
2025-11-23 09:26:12 -08:00
parent 93f5481f94
commit a97e38fc6e
9 changed files with 63 additions and 12 deletions

View File

@@ -1,5 +1,6 @@
import express, { Request, Response, NextFunction } from 'express';
import cookieParser from 'cookie-parser';
import { getPool } from './src/services/db/connection';
import passport from './src/routes/passport';
import { logger } from './src/services/logger';
@@ -23,6 +24,17 @@ logger.info(` Host: ${process.env.DB_HOST}`);
logger.info(` Port: ${process.env.DB_PORT}`);
logger.info(` User: ${process.env.DB_USER}`);
logger.info(` Database: ${process.env.DB_DATABASE}`);
// Query the users table to see what the server process sees on startup.
getPool().query('SELECT id, email, role FROM public.users u JOIN public.profiles p ON u.id = p.id')
.then(res => {
logger.debug('[SERVER PROCESS] Users found in DB on startup:');
console.table(res.rows);
})
.catch(err => {
logger.error('[SERVER PROCESS] Could not query users table on startup.', { err });
});
logger.info('-----------------------------------------------\n');
const app = express();

View File

@@ -177,6 +177,12 @@ async function main() {
}
logger.info(`Seeded shopping list "Weekly Groceries" with ${shoppingListItems.length} items for Test User.`);
// --- SEED SCRIPT DEBUG LOGGING ---
const allUsersInDb = await client.query('SELECT id, email, role FROM public.users u JOIN public.profiles p ON u.id = p.id');
logger.debug('[SEED SCRIPT] Final state of users table after seeding:');
console.table(allUsersInDb.rows);
// --- END DEBUG LOGGING ---
await client.query('COMMIT');
logger.info('✅ Database seeding completed successfully!');

View File

@@ -92,7 +92,21 @@ router.post('/register', async (req: Request, res: Response, next: NextFunction)
// Login Route
router.post('/login', (req: Request, res: Response, next: NextFunction) => {
passport.authenticate('local', { session: false }, (err: Error, user: Express.User | false, info: { message: string }) => {
passport.authenticate('local', { session: false }, async (err: Error, user: Express.User | false, info: { message: string }) => {
// --- LOGIN ROUTE DEBUG LOGGING ---
logger.debug(`[API /login] Received login request for email: ${req.body.email}`);
if (err) logger.error('[API /login] Passport reported an error.', { err });
if (!user) logger.warn('[API /login] Passport reported NO USER found.', { info });
if (user) logger.info('[API /login] Passport reported USER FOUND.', { user });
try {
const allUsersInDb = await db.getPool().query('SELECT id, email, role FROM public.users u JOIN public.profiles p ON u.id = p.id');
logger.debug('[API /login] Current users in DB from SERVER perspective:');
console.table(allUsersInDb.rows);
} catch (dbError) {
logger.error('[API /login] Could not query users table for debugging.', { dbError });
}
// --- END DEBUG LOGGING ---
const { rememberMe } = req.body;
if (err) {
logger.error('Login authentication error in /login route:', { error: err });
@@ -133,8 +147,11 @@ router.post('/forgot-password', forgotPasswordLimiter, async (req: Request, res:
}
try {
logger.debug(`[API /forgot-password] Received request for email: ${email}`);
const user = await db.findUserByEmail(email);
let token: string | undefined;
logger.debug(`[API /forgot-password] Database search result for ${email}:`, { user: user ? { id: user.id, email: user.email } : 'NOT FOUND' });
if (user) {
token = crypto.randomBytes(32).toString('hex');
const saltRounds = 10;

View File

@@ -155,11 +155,15 @@ router.delete('/users/account', async (req: Request, res: Response) => {
return res.status(400).json({ message: 'Password is required for account deletion.' });
}
logger.info(`Account deletion requested for user ID: ${authenticatedUser.id}`);
logger.info(`[API /users/account] Account deletion requested for user ID: ${authenticatedUser.id}`);
try {
const userWithHash = await db.findUserWithPasswordHashById(authenticatedUser.id);
// --- DELETE ACCOUNT DEBUG LOGGING ---
logger.debug(`[API /users/account] DB search result for user ID ${authenticatedUser.id}:`, { user: userWithHash ? 'FOUND' : 'NOT FOUND' });
// --- END DEBUG LOGGING ---
if (!userWithHash || !userWithHash.password_hash) {
return res.status(404).json({ message: 'User not found or is an OAuth user.' });
}

View File

@@ -115,6 +115,13 @@ export const apiFetch = async (url: string, options: RequestInit = {}, tokenOver
}
}
// --- DEBUG LOGGING for failed requests ---
if (!response.ok) {
const responseText = await response.clone().text();
logger.error(`apiFetch: Request to ${fullUrl} failed with status ${response.status}. Response body:`, responseText);
}
// --- END DEBUG LOGGING ---
return response;
};

View File

@@ -9,6 +9,9 @@ import { logger } from '../logger';
let poolInstance: Pool | undefined;
const createPool = (): Pool => {
// Add a unique ID to each pool instance for definitive tracking in logs.
const poolId = Math.random().toString(36).substring(2, 8);
// --- START DEBUG LOGGING ---
// Log the database connection details being used by the server process.
// This helps confirm it's using the correct .env file for the environment.
@@ -17,6 +20,7 @@ const createPool = (): Pool => {
logger.info(` Port: ${process.env.DB_PORT}`);
logger.info(` User: ${process.env.DB_USER}`);
logger.info(` Database: ${process.env.DB_DATABASE}`);
logger.info(` Pool Instance ID: ${poolId}`);
logger.info('----------------------------------------------------');
const newPool = new Pool({

View File

@@ -14,9 +14,10 @@ type LogLevel = 'INFO' | 'WARN' | 'ERROR' | 'DEBUG';
* methods. Using `unknown[]` is more type-safe than `any[]` and satisfies the linter.
*/
const log = <T extends unknown[]>(level: LogLevel, message: string, ...args: T) => {
const pid = process.pid;
const timestamp = getTimestamp();
// We construct the log message with a timestamp and level for better context.
const logMessage = `[${timestamp}] [${level}] ${message}`;
// We construct the log message with a timestamp, PID, and level for better context.
const logMessage = `[${timestamp}] [PID:${pid}] [${level}] ${message}`;
switch (level) {
case 'INFO':

View File

@@ -6,20 +6,20 @@ import { execSync } from 'child_process';
let serverProcess: ChildProcess;
export async function setup() {
console.log('\n--- Running Integration Test 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('Resetting and seeding test database...');
console.log(`\n[PID:${process.pid}] Running database seed script...`);
execSync('npm run db:reset:test', { stdio: 'inherit' });
console.log('✅ Test database is ready.');
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('Starting backend server for integration tests...');
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');
@@ -27,7 +27,7 @@ export async function setup() {
// --- NEW LOGGING START ---
// Listen for premature exit to debug crashes immediately
serverProcess.on('exit', (code, signal) => {
if (code !== null && code !== 0) {
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');
}
@@ -68,7 +68,7 @@ export async function setup() {
throw new Error(`Server process exited with code ${serverProcess.exitCode}`);
}
if (await pingTestBackend()) {
if (await pingTestBackend().catch(() => false)) {
console.log('✅ Backend server is running and responsive.');
return;
}
@@ -77,7 +77,7 @@ export async function setup() {
if (serverProcess.exitCode !== null) throw e;
logger.debug('Ping failed while waiting for server, this is expected.', { error: e });
}
console.log(`Waiting for backend server... (attempt ${i + 1}/${maxRetries})`);
console.log(`[PID:${process.pid}] Waiting for backend server... (attempt ${i + 1}/${maxRetries})`);
await new Promise(resolve => setTimeout(resolve, retryDelay));
}
@@ -87,7 +87,7 @@ export async function setup() {
}
export async function teardown() {
console.log('--- Integration Test 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();

View File