fix unit tests
Some checks failed
Deploy to Web Server flyer-crawler.projectium.com / deploy (push) Failing after 3m43s

This commit is contained in:
2025-11-30 14:50:28 -08:00
parent cb80145ea0
commit 6174cf7d97
5 changed files with 38 additions and 12 deletions

View File

@@ -82,6 +82,9 @@ DROP TABLE IF EXISTS public.schema_info CASCADE;
-- a completely clean public schema if the extension were to be re-installed.
-- It's generally safe to include these in a full reset script.
DROP TABLE IF EXISTS public.spatial_ref_sys CASCADE;
DROP TABLE IF EXISTS public.geometry_columns CASCADE;
DROP TABLE IF EXISTS public.geography_columns CASCADE;
-- These tables are owned by the 'postgis' extension and cannot be dropped directly.
-- Doing so would require dropping the extension itself, which is not the goal of this script.
-- We only want to reset the application's data, not the database's extensions.
-- DROP TABLE IF EXISTS public.spatial_ref_sys CASCADE;
-- DROP TABLE IF EXISTS public.geometry_columns CASCADE;
-- DROP TABLE IF EXISTS public.geography_columns CASCADE;

View File

@@ -2404,6 +2404,7 @@ BEGIN
'A new flyer for ' || (SELECT name FROM public.stores WHERE store_id = NEW.store_id) || ' has been uploaded.',
'file-text',
jsonb_build_object(
'flyer_id', NEW.flyer_id,
'store_name', (SELECT name FROM public.stores WHERE store_id = NEW.store_id),
'valid_from', to_char(NEW.valid_from, 'YYYY-MM-DD'),
'valid_to', to_char(NEW.valid_to, 'YYYY-MM-DD')

View File

@@ -72,7 +72,13 @@ describe('Auth Routes (/api/auth)', () => {
// 1. User does not exist
mockedDb.findUserByEmail.mockResolvedValue(undefined);
// 2. Mock the user creation and token saving
const mockNewUser: Awaited<ReturnType<typeof db.createUser>> = { user_id: 'new-user-id', email: newUserEmail };
// This mock now matches the nested structure of the UserProfile type.
const mockNewUser: Awaited<ReturnType<typeof db.createUser>> = {
user_id: 'new-user-id',
user: { user_id: 'new-user-id', email: newUserEmail },
role: 'user',
points: 0
};
mockedDb.createUser.mockResolvedValue(mockNewUser);
mockedDb.saveRefreshToken.mockResolvedValue();
mockedDb.logActivity.mockResolvedValue();

View File

@@ -68,17 +68,17 @@ router.post('/register', async (req: Request, res: Response, next: NextFunction)
logger.info(`Hashing password for new user: ${email}`);
const newUser = await db.createUser(email, hashedPassword, { full_name, avatar_url });
logger.info(`Successfully created new user in DB: ${newUser.email} (ID: ${newUser.user_id})`);
logger.info(`Successfully created new user in DB: ${newUser.user.email} (ID: ${newUser.user_id})`);
// Use the new standardized logging function
await db.logActivity({
userId: newUser.user_id,
action: 'user_registered',
displayText: `${newUser.email} has registered.`,
displayText: `${newUser.user.email} has registered.`,
icon: 'user-plus',
});
const payload = { user_id: newUser.user_id, email: newUser.email };
const payload = { user_id: newUser.user_id, email: newUser.user.email };
const token = jwt.sign(payload, JWT_SECRET, { expiresIn: '1h' });
const refreshToken = crypto.randomBytes(64).toString('hex');

View File

@@ -2,7 +2,7 @@
import { getPool } from './connection';
import { logger } from '../logger';
import { UniqueConstraintError, ForeignKeyConstraintError } from './errors';
import { Profile, MasterGroceryItem, ShoppingList, ActivityLogItem, User } from '../../types';
import { Profile, MasterGroceryItem, ShoppingList, ActivityLogItem, User, UserProfile } from '../../types';
import { getShoppingLists } from './shopping';
import { getWatchedItems } from './personalization';
@@ -51,7 +51,7 @@ export async function createUser(
email: string,
passwordHash: string | null,
profileData: { full_name?: string; avatar_url?: string }
): Promise<User> {
): Promise<UserProfile> {
// Use a client from the pool to run multiple queries in a transaction
const client = await getPool().connect();
@@ -62,23 +62,39 @@ export async function createUser(
}
try {
logger.debug(`[DB createUser] Starting transaction for email: ${email}`);
// Start the transaction
await client.query('BEGIN');
// Use 'set_config' to safely pass parameters to a configuration variable.
// The previous 'SET LOCAL var = $1' syntax is invalid in Postgres/node-postgres.
// The third argument 'true' makes the setting local to the transaction.
await client.query("SELECT set_config('my_app.user_metadata', $1, true)", [JSON.stringify(profileData)]);
logger.debug(`[DB createUser] Session metadata set for ${email}.`);
// Insert the new user into the 'users' table. This will fire the trigger.
const res = await client.query<User>(
const userInsertRes = await client.query<{ user_id: string }>(
'INSERT INTO public.users (email, password_hash) VALUES ($1, $2) RETURNING user_id, email',
[email, passwordHash]
);
const newUserId = userInsertRes.rows[0].user_id;
logger.debug(`[DB createUser] Inserted into users table. New user ID: ${newUserId}`);
// After the trigger has run, fetch the complete profile data.
// This is the crucial step to ensure we return the full object.
const profileQuery = `
SELECT u.user_id, u.email, p.full_name, p.avatar_url, p.role, p.points, p.preferences
FROM public.users u
JOIN public.profiles p ON u.user_id = p.user_id
WHERE u.user_id = $1;
`;
const finalProfileRes = await client.query<UserProfile>(profileQuery, [newUserId]);
const fullUserProfile = finalProfileRes.rows[0];
logger.debug(`[DB createUser] Fetched full profile for new user:`, { user: fullUserProfile });
// Commit the transaction
await client.query('COMMIT');
return res.rows[0];
logger.debug(`[DB createUser] Transaction committed for ${email}.`);
return fullUserProfile;
} catch (error) {
// If any query fails, roll back the entire transaction
try {