Add comprehensive tests for hooks, middleware, and routes
Some checks are pending
Deploy to Test Environment / deploy-to-test (push) Has started running

- Implement tests for `useFlyers`, `useMasterItems`, `useModal`, `useUserData` hooks to ensure correct functionality and error handling.
- Create tests for `fileUpload.middleware` and `validation.middleware` to validate file uploads and request data.
- Add tests for `AddressForm` and `AuthView` components to verify rendering, user interactions, and API calls.
- Develop tests for `deals.routes` to check authentication and response for best prices on watched items.
This commit is contained in:
2025-12-13 21:30:43 -08:00
parent 424cbaf0d4
commit 77454b04c2
20 changed files with 1358 additions and 269 deletions

View File

@@ -1,22 +1,28 @@
// src/services/db/deals.repository.ts
// src/services/db/deals.db.ts
import { getPool } from './connection.db';
import { WatchedItemDeal } from '../../types';
import { Pool } from 'pg';
import type { Pool, PoolClient } from 'pg';
import type { Logger } from 'pino';
import { logger as globalLogger } from '../logger.server';
export class DealsRepository {
private pool: Pool;
private db: Pool | PoolClient;
constructor() {
this.pool = getPool();
constructor(db: Pool | PoolClient = getPool()) {
this.db = db;
}
/**
* Finds the best current sale price for each of a user's watched items.
* It considers only currently active flyers and handles ties by preferring the deal
* that is valid for the longest time.
*
* @param userId - The ID of the user whose watched items are being checked.
* @param logger - The logger instance for context-specific logging.
* @returns A promise that resolves to an array of WatchedItemDeal objects.
*/
async findBestPricesForWatchedItems(userId: string): Promise<WatchedItemDeal[]> {
async findBestPricesForWatchedItems(userId: string, logger: Logger = globalLogger): Promise<WatchedItemDeal[]> {
logger.debug({ userId }, 'Finding best prices for watched items.');
const query = `
WITH UserWatchedItems AS (
-- Select all items the user is watching
@@ -31,6 +37,7 @@ export class DealsRepository {
s.name AS store_name,
f.flyer_id,
f.valid_to,
-- Rank prices for each item, lowest first. In case of a tie, the deal that ends later is preferred.
ROW_NUMBER() OVER(PARTITION BY fi.master_item_id ORDER BY fi.price_in_cents ASC, f.valid_to DESC) as rn
FROM flyer_items fi
JOIN flyers f ON fi.flyer_id = f.flyer_id
@@ -53,8 +60,13 @@ export class DealsRepository {
WHERE rn = 1
ORDER BY item_name;
`;
const { rows } = await this.pool.query(query, [userId]);
return rows;
try {
const { rows } = await this.db.query<WatchedItemDeal>(query, [userId]);
return rows;
} catch (error) {
logger.error({ err: error }, 'Database error in findBestPricesForWatchedItems');
throw error; // Re-throw the original error to be handled by the global error handler
}
}
}

View File

@@ -72,7 +72,7 @@ export class GamificationRepository {
if (error instanceof Error && 'code' in error && error.code === '23503') {
throw new ForeignKeyConstraintError('The specified user or achievement does not exist.');
}
logger.error({ err: error, userId, achievementName }, 'Database error in awardAchievement');
logger.error({ err: error, achievementName }, 'Database error in awardAchievement');
throw new Error('Failed to award achievement.');
}
}