Add comprehensive tests for hooks, middleware, and routes
Some checks are pending
Deploy to Test Environment / deploy-to-test (push) Has started running
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:
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user