Some checks failed
Deploy to Test Environment / deploy-to-test (push) Failing after 1m17s
146 lines
5.0 KiB
TypeScript
146 lines
5.0 KiB
TypeScript
// src/routes/admin.stats.routes.test.ts
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import supertest from 'supertest';
|
|
import type { Request, Response, NextFunction } from 'express';
|
|
import { createMockUserProfile } from '../tests/utils/mockFactories';
|
|
import type { UserProfile } from '../types';
|
|
import { createTestApp } from '../tests/utils/createTestApp';
|
|
|
|
vi.mock('../services/db/index.db', () => ({
|
|
adminRepo: {
|
|
getApplicationStats: vi.fn(),
|
|
getDailyStatsForLast30Days: vi.fn(),
|
|
},
|
|
flyerRepo: {},
|
|
recipeRepo: {},
|
|
userRepo: {},
|
|
personalizationRepo: {},
|
|
notificationRepo: {},
|
|
}));
|
|
|
|
// Mock other dependencies
|
|
vi.mock('../services/db/flyer.db');
|
|
vi.mock('../services/db/recipe.db');
|
|
vi.mock('../services/db/user.db');
|
|
vi.mock('node:fs/promises');
|
|
vi.mock('../services/backgroundJobService');
|
|
vi.mock('../services/geocodingService.server');
|
|
vi.mock('../services/queueService.server');
|
|
vi.mock('../services/queues.server');
|
|
vi.mock('../services/workers.server');
|
|
vi.mock('../services/monitoringService.server');
|
|
vi.mock('../services/cacheService.server');
|
|
vi.mock('../services/userService');
|
|
vi.mock('../services/brandService');
|
|
vi.mock('../services/receiptService.server');
|
|
vi.mock('../services/aiService.server');
|
|
vi.mock('../config/env', () => ({
|
|
config: {
|
|
database: { host: 'localhost', port: 5432, user: 'test', password: 'test', name: 'test' },
|
|
redis: { url: 'redis://localhost:6379' },
|
|
auth: { jwtSecret: 'test-secret' },
|
|
server: { port: 3000, host: 'localhost' },
|
|
},
|
|
isAiConfigured: vi.fn().mockReturnValue(false),
|
|
parseConfig: vi.fn(),
|
|
}));
|
|
vi.mock('@bull-board/api');
|
|
vi.mock('@bull-board/api/bullMQAdapter');
|
|
vi.mock('@bull-board/express', () => ({
|
|
ExpressAdapter: class {
|
|
setBasePath() {}
|
|
getRouter() {
|
|
return (req: Request, res: Response, next: NextFunction) => next();
|
|
}
|
|
},
|
|
}));
|
|
|
|
// Import the router AFTER all mocks are defined.
|
|
import adminRouter from './admin.routes';
|
|
|
|
// Import the mocked modules to control them
|
|
import { adminRepo } from '../services/db/index.db';
|
|
|
|
// Mock the logger
|
|
vi.mock('../services/logger.server', async () => {
|
|
const { mockLogger, createMockLogger } = await import('../tests/utils/mockLogger');
|
|
return {
|
|
logger: mockLogger,
|
|
createScopedLogger: vi.fn(() => createMockLogger()),
|
|
};
|
|
});
|
|
|
|
// Mock the passport middleware
|
|
// Note: admin.routes.ts imports from '../config/passport', so we mock that path
|
|
vi.mock('../config/passport', () => ({
|
|
default: {
|
|
authenticate: vi.fn(() => (req: Request, res: Response, next: NextFunction) => {
|
|
if (!req.user) return res.status(401).json({ message: 'Unauthorized' });
|
|
next();
|
|
}),
|
|
},
|
|
isAdmin: (req: Request, res: Response, next: NextFunction) => {
|
|
const user = req.user as UserProfile | undefined;
|
|
if (user && user.role === 'admin') next();
|
|
else res.status(403).json({ message: 'Forbidden: Administrator access required.' });
|
|
},
|
|
}));
|
|
|
|
describe('Admin Stats Routes (/api/admin/stats)', () => {
|
|
const adminUser = createMockUserProfile({ role: 'admin' });
|
|
// Create a single app instance with an admin user for all tests in this suite.
|
|
const app = createTestApp({
|
|
router: adminRouter,
|
|
basePath: '/api/admin',
|
|
authenticatedUser: adminUser,
|
|
});
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe('GET /stats', () => {
|
|
it('should return application stats on success', async () => {
|
|
const mockStats = {
|
|
flyerCount: 150,
|
|
userCount: 42,
|
|
flyerItemCount: 10000,
|
|
storeCount: 12,
|
|
pendingCorrectionCount: 5,
|
|
recipeCount: 50,
|
|
};
|
|
vi.mocked(adminRepo.getApplicationStats).mockResolvedValue(mockStats);
|
|
const response = await supertest(app).get('/api/admin/stats');
|
|
expect(response.status).toBe(200);
|
|
expect(response.body.data).toEqual(mockStats);
|
|
});
|
|
|
|
it('should return 500 if the database call fails', async () => {
|
|
vi.mocked(adminRepo.getApplicationStats).mockRejectedValue(new Error('DB Error'));
|
|
const response = await supertest(app).get('/api/admin/stats');
|
|
expect(response.status).toBe(500);
|
|
expect(response.body.error.message).toBe('DB Error');
|
|
});
|
|
});
|
|
|
|
describe('GET /stats/daily', () => {
|
|
it('should return daily stats on success', async () => {
|
|
const mockDailyStats = [
|
|
{ date: '2024-01-01', new_users: 5, new_flyers: 10 },
|
|
{ date: '2024-01-02', new_users: 3, new_flyers: 8 },
|
|
];
|
|
vi.mocked(adminRepo.getDailyStatsForLast30Days).mockResolvedValue(mockDailyStats);
|
|
const response = await supertest(app).get('/api/admin/stats/daily');
|
|
expect(response.status).toBe(200);
|
|
expect(response.body.data).toEqual(mockDailyStats);
|
|
});
|
|
|
|
it('should return 500 if the database call fails', async () => {
|
|
vi.mocked(adminRepo.getDailyStatsForLast30Days).mockRejectedValue(new Error('DB Error'));
|
|
const response = await supertest(app).get('/api/admin/stats/daily');
|
|
expect(response.status).toBe(500);
|
|
expect(response.body.error.message).toBe('DB Error');
|
|
});
|
|
});
|
|
});
|