All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 16m42s
127 lines
4.5 KiB
TypeScript
127 lines
4.5 KiB
TypeScript
// src/routes/deals.routes.test.ts
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import supertest from 'supertest';
|
|
import type { Request, Response, NextFunction } from 'express';
|
|
import { createMockUserProfile, createMockWatchedItemDeal } from '../tests/utils/mockFactories';
|
|
import type { WatchedItemDeal } from '../types';
|
|
import { createTestApp } from '../tests/utils/createTestApp';
|
|
|
|
// 1. Mock the Service Layer directly.
|
|
vi.mock('../services/db/deals.db', () => ({
|
|
dealsRepo: {
|
|
findBestPricesForWatchedItems: vi.fn(),
|
|
},
|
|
}));
|
|
|
|
// Import the router and mocked repo AFTER all mocks are defined.
|
|
import dealsRouter from './deals.routes';
|
|
import { dealsRepo } from '../services/db/deals.db';
|
|
import { mockLogger } from '../tests/utils/mockLogger';
|
|
|
|
// Mock the logger to keep test output clean
|
|
vi.mock('../services/logger.server', async () => ({
|
|
// Use async import to avoid hoisting issues with mockLogger
|
|
logger: (await import('../tests/utils/mockLogger')).mockLogger,
|
|
}));
|
|
|
|
// Mock the passport middleware
|
|
vi.mock('../config/passport', () => ({
|
|
default: {
|
|
authenticate: vi.fn(() => (req: Request, res: Response, next: NextFunction) => {
|
|
// If req.user is not set by the test setup, simulate unauthenticated access.
|
|
if (!req.user) {
|
|
return res.status(401).json({ message: 'Unauthorized' });
|
|
}
|
|
// If req.user is set, proceed as an authenticated user.
|
|
next();
|
|
}),
|
|
},
|
|
requireAuth: vi.fn((req: Request, res: Response, next: NextFunction) => {
|
|
// If req.user is not set by the test setup, simulate unauthenticated access.
|
|
if (!req.user) {
|
|
return res.status(401).json({ message: 'Unauthorized' });
|
|
}
|
|
// If req.user is set, proceed as an authenticated user.
|
|
next();
|
|
}),
|
|
}));
|
|
|
|
// Define a reusable matcher for the logger object.
|
|
const expectLogger = expect.objectContaining({
|
|
info: expect.any(Function),
|
|
error: expect.any(Function),
|
|
});
|
|
|
|
describe('Deals Routes (/api/users/deals)', () => {
|
|
const mockUser = createMockUserProfile({ user: { user_id: 'user-123', email: 'test@test.com' } });
|
|
const basePath = '/api/users/deals';
|
|
const authenticatedApp = createTestApp({
|
|
router: dealsRouter,
|
|
basePath,
|
|
authenticatedUser: mockUser,
|
|
});
|
|
const unauthenticatedApp = createTestApp({ router: dealsRouter, basePath });
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe('GET /best-watched-prices', () => {
|
|
it('should return 401 Unauthorized if user is not authenticated', async () => {
|
|
const response = await supertest(unauthenticatedApp).get(
|
|
'/api/users/deals/best-watched-prices',
|
|
);
|
|
expect(response.status).toBe(401);
|
|
});
|
|
|
|
it('should return a list of deals for an authenticated user', async () => {
|
|
const mockDeals: WatchedItemDeal[] = [createMockWatchedItemDeal({ item_name: 'Apples' })];
|
|
vi.mocked(dealsRepo.findBestPricesForWatchedItems).mockResolvedValue(mockDeals);
|
|
|
|
const response = await supertest(authenticatedApp).get(
|
|
'/api/users/deals/best-watched-prices',
|
|
);
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body.data).toEqual(mockDeals);
|
|
expect(dealsRepo.findBestPricesForWatchedItems).toHaveBeenCalledWith(
|
|
mockUser.user.user_id,
|
|
expectLogger,
|
|
);
|
|
expect(mockLogger.info).toHaveBeenCalledWith(
|
|
{ dealCount: 1 },
|
|
'Successfully fetched best watched item deals.',
|
|
);
|
|
});
|
|
|
|
it('should return 500 if the database call fails', async () => {
|
|
const dbError = new Error('DB Error');
|
|
vi.mocked(dealsRepo.findBestPricesForWatchedItems).mockRejectedValue(dbError);
|
|
|
|
const response = await supertest(authenticatedApp).get(
|
|
'/api/users/deals/best-watched-prices',
|
|
);
|
|
expect(response.status).toBe(500);
|
|
expect(response.body.error.message).toBe('DB Error');
|
|
expect(mockLogger.error).toHaveBeenCalledWith(
|
|
{ error: dbError },
|
|
'Error fetching best watched item deals.',
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('Rate Limiting', () => {
|
|
it('should apply userReadLimiter to GET /best-watched-prices', async () => {
|
|
vi.mocked(dealsRepo.findBestPricesForWatchedItems).mockResolvedValue([]);
|
|
|
|
const response = await supertest(authenticatedApp)
|
|
.get('/api/users/deals/best-watched-prices')
|
|
.set('X-Test-Rate-Limit-Enable', 'true');
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.headers).toHaveProperty('ratelimit-limit');
|
|
expect(parseInt(response.headers['ratelimit-limit'])).toBe(100);
|
|
});
|
|
});
|
|
});
|