renaming
All checks were successful
Deploy to Web Server flyer-crawler.projectium.com / deploy (push) Successful in 4m31s
All checks were successful
Deploy to Web Server flyer-crawler.projectium.com / deploy (push) Successful in 4m31s
This commit is contained in:
20
server.ts
20
server.ts
@@ -5,19 +5,19 @@ import cookieParser from 'cookie-parser';
|
||||
import listEndpoints from 'express-list-endpoints';
|
||||
import { getPool } from './src/services/db/connection.db';
|
||||
|
||||
import passport from './src/routes/passport';
|
||||
import passport from './src/routes/passport.routes';
|
||||
import { logger } from './src/services/logger.server';
|
||||
|
||||
// Import routers
|
||||
import authRouter from './src/routes/auth';
|
||||
import publicRouter from './src/routes/public'; // This seems to be missing from the original file list, but is required.
|
||||
import userRouter from './src/routes/user';
|
||||
import adminRouter from './src/routes/admin';
|
||||
import aiRouter from './src/routes/ai';
|
||||
import budgetRouter from './src/routes/budget';
|
||||
import gamificationRouter from './src/routes/gamification';
|
||||
import systemRouter from './src/routes/system';
|
||||
import healthRouter from './src/routes/health';
|
||||
import authRouter from './src/routes/auth.routes';
|
||||
import publicRouter from './src/routes/public.routes'; // This seems to be missing from the original file list, but is required.
|
||||
import userRouter from './src/routes/user.routes';
|
||||
import adminRouter from './src/routes/admin.routes';
|
||||
import aiRouter from './src/routes/ai.routes';
|
||||
import budgetRouter from './src/routes/budget.routes';
|
||||
import gamificationRouter from './src/routes/gamification.routes';
|
||||
import systemRouter from './src/routes/system.routes';
|
||||
import healthRouter from './src/routes/health.routes';
|
||||
import { errorHandler } from './src/middleware/errorHandler';
|
||||
import { startBackgroundJobs } from './src/services/backgroundJobService';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// src/routes/admin.db.ts
|
||||
import { Router, NextFunction } from 'express';
|
||||
import passport from './passport';
|
||||
import { isAdmin } from './passport'; // Correctly imported
|
||||
import passport from './passport.routes';
|
||||
import { isAdmin } from './passport.routes'; // Correctly imported
|
||||
import multer from 'multer';
|
||||
|
||||
import * as db from '../services/db/index.db';
|
||||
@@ -4,7 +4,7 @@ import supertest from 'supertest';
|
||||
import express, { Request, Response, NextFunction } from 'express';
|
||||
import path from 'node:path';
|
||||
import fs from 'node:fs/promises';
|
||||
import adminRouter from './admin'; // Correctly imported
|
||||
import adminRouter from './admin.routes'; // Correctly imported
|
||||
import { UserProfile } from '../types';
|
||||
|
||||
// Mock the specific DB modules used by the admin router.
|
||||
@@ -12,12 +12,14 @@ import { UserProfile } from '../types';
|
||||
vi.mock('../services/db/admin.db');
|
||||
vi.mock('../services/db/flyer.db');
|
||||
vi.mock('../services/db/recipe.db');
|
||||
vi.mock('../services/db/user.db'); // Add mock for user.db
|
||||
|
||||
// Import the mocked modules to control them in tests.
|
||||
import * as adminDb from '../services/db/admin.db';
|
||||
import * as flyerDb from '../services/db/flyer.db';
|
||||
import * as recipeDb from '../services/db/recipe.db';
|
||||
const mockedDb = { ...adminDb, ...flyerDb, ...recipeDb } as Mocked<typeof adminDb & typeof flyerDb & typeof recipeDb>;
|
||||
import * as userDb from '../services/db/user.db'; // Import the mocked user.db
|
||||
const mockedDb = { ...adminDb, ...flyerDb, ...recipeDb, ...userDb } as Mocked<typeof adminDb & typeof flyerDb & typeof recipeDb & typeof userDb>;
|
||||
|
||||
// Mock the logger to keep test output clean
|
||||
vi.mock('../services/logger.server', () => ({
|
||||
@@ -53,7 +55,7 @@ vi.mock('./passport', () => ({
|
||||
}));
|
||||
|
||||
// We need to import the mocked 'isAdmin' so we can change its behavior in tests.
|
||||
import { isAdmin } from './passport';
|
||||
import { isAdmin } from './passport.routes';
|
||||
const mockedIsAdmin = isAdmin as Mock;
|
||||
|
||||
// Create a minimal Express app to host our router
|
||||
@@ -118,7 +120,7 @@ describe('Admin Routes (/api/admin)', () => {
|
||||
|
||||
it('GET /corrections should return corrections data', async () => {
|
||||
// Arrange
|
||||
const mockCorrections: Awaited<ReturnType<typeof db.getSuggestedCorrections>> = [{ suggested_correction_id: 1, flyer_item_id: 1, user_id: '1', correction_type: 'price', suggested_value: 'New Price', status: 'pending', created_at: new Date().toISOString() }];
|
||||
const mockCorrections: Awaited<ReturnType<typeof mockedDb.getSuggestedCorrections>> = [{ suggested_correction_id: 1, flyer_item_id: 1, user_id: '1', correction_type: 'price', suggested_value: 'New Price', status: 'pending', created_at: new Date().toISOString() }];
|
||||
vi.mocked(adminDb.getSuggestedCorrections).mockResolvedValue(mockCorrections);
|
||||
|
||||
// Act
|
||||
@@ -133,7 +135,7 @@ describe('Admin Routes (/api/admin)', () => {
|
||||
describe('GET /brands', () => {
|
||||
it('should return a list of all brands on success', async () => {
|
||||
// Arrange
|
||||
const mockBrands: Awaited<ReturnType<typeof db.getAllBrands>> = [
|
||||
const mockBrands: Awaited<ReturnType<typeof mockedDb.getAllBrands>> = [
|
||||
{ brand_id: 1, name: 'Brand A', logo_url: '/path/a.png' },
|
||||
{ brand_id: 2, name: 'Brand B', logo_url: '/path/b.png' },
|
||||
];
|
||||
@@ -189,7 +191,7 @@ describe('Admin Routes (/api/admin)', () => {
|
||||
const mockDailyStats = [
|
||||
{ date: '2024-01-01', new_users: 5, new_flyers: 10 },
|
||||
{ date: '2024-01-02', new_users: 3, new_flyers: 8 },
|
||||
] as Awaited<ReturnType<typeof db.getDailyStatsForLast30Days>>;
|
||||
] as Awaited<ReturnType<typeof mockedDb.getDailyStatsForLast30Days>>;
|
||||
vi.mocked(adminDb.getDailyStatsForLast30Days).mockResolvedValue(mockDailyStats);
|
||||
|
||||
// Act
|
||||
@@ -211,7 +213,7 @@ describe('Admin Routes (/api/admin)', () => {
|
||||
describe('GET /unmatched-items', () => {
|
||||
it('should return a list of unmatched items on success', async () => {
|
||||
// Arrange
|
||||
const mockUnmatchedItems: Awaited<ReturnType<typeof db.getUnmatchedFlyerItems>> = [
|
||||
const mockUnmatchedItems: Awaited<ReturnType<typeof mockedDb.getUnmatchedFlyerItems>> = [
|
||||
{ unmatched_flyer_item_id: 1, status: 'pending', created_at: new Date().toISOString(), flyer_item_id: 101, flyer_item_name: 'Ketchup Chips', price_display: '$3.00', flyer_id: 1, store_name: 'Test Store' },
|
||||
{ unmatched_flyer_item_id: 2, status: 'pending', created_at: new Date().toISOString(), flyer_item_id: 102, flyer_item_name: 'Mystery Soda', price_display: '2 for $4.00', flyer_id: 1, store_name: 'Test Store' },
|
||||
];
|
||||
@@ -306,7 +308,7 @@ describe('Admin Routes (/api/admin)', () => {
|
||||
// Arrange
|
||||
const correctionId = 101;
|
||||
const requestBody = { suggested_value: 'A new corrected value' };
|
||||
const mockUpdatedCorrection: Awaited<ReturnType<typeof db.updateSuggestedCorrection>> = { suggested_correction_id: correctionId, flyer_item_id: 1, user_id: '1', correction_type: 'price', status: 'pending', created_at: new Date().toISOString(), ...requestBody };
|
||||
const mockUpdatedCorrection: Awaited<ReturnType<typeof mockedDb.updateSuggestedCorrection>> = { suggested_correction_id: correctionId, flyer_item_id: 1, user_id: '1', correction_type: 'price', status: 'pending', created_at: new Date().toISOString(), ...requestBody };
|
||||
vi.mocked(adminDb.updateSuggestedCorrection).mockResolvedValue(mockUpdatedCorrection);
|
||||
|
||||
// Act: Use .send() to include a request body
|
||||
@@ -415,7 +417,7 @@ describe('Admin Routes (/api/admin)', () => {
|
||||
// Arrange
|
||||
const recipeId = 201;
|
||||
const requestBody = { status: 'public' as const };
|
||||
const mockUpdatedRecipe: Awaited<ReturnType<typeof db.updateRecipeStatus>> = { recipe_id: recipeId, status: 'public', name: 'Test Recipe', avg_rating: 0, rating_count: 0, fork_count: 0, created_at: new Date().toISOString() };
|
||||
const mockUpdatedRecipe: Awaited<ReturnType<typeof mockedDb.updateRecipeStatus>> = { recipe_id: recipeId, status: 'public', name: 'Test Recipe', avg_rating: 0, rating_count: 0, fork_count: 0, created_at: new Date().toISOString() };
|
||||
vi.mocked(adminDb.updateRecipeStatus).mockResolvedValue(mockUpdatedRecipe);
|
||||
|
||||
// Act
|
||||
@@ -452,7 +454,7 @@ describe('Admin Routes (/api/admin)', () => {
|
||||
// Arrange
|
||||
const commentId = 301;
|
||||
const requestBody = { status: 'hidden' as const };
|
||||
const mockUpdatedComment: Awaited<ReturnType<typeof db.updateRecipeCommentStatus>> = { recipe_comment_id: commentId, recipe_id: 1, user_id: '1', status: 'hidden', content: 'Test Comment', created_at: new Date().toISOString() };
|
||||
const mockUpdatedComment: Awaited<ReturnType<typeof mockedDb.updateRecipeCommentStatus>> = { recipe_comment_id: commentId, recipe_id: 1, user_id: '1', status: 'hidden', content: 'Test Comment', created_at: new Date().toISOString() };
|
||||
vi.mocked(adminDb.updateRecipeCommentStatus).mockResolvedValue(mockUpdatedComment);
|
||||
|
||||
// Act
|
||||
@@ -478,7 +480,7 @@ describe('Admin Routes (/api/admin)', () => {
|
||||
describe('GET /users', () => {
|
||||
it('should return a list of all users on success', async () => {
|
||||
// Arrange
|
||||
const mockUsers: Awaited<ReturnType<typeof db.getAllUsers>> = [
|
||||
const mockUsers: Awaited<ReturnType<typeof mockedDb.getAllUsers>> = [
|
||||
{ user_id: '1', email: 'user1@test.com', role: 'user', created_at: new Date().toISOString(), full_name: 'User One', avatar_url: null },
|
||||
{ user_id: '2', email: 'user2@test.com', role: 'admin', created_at: new Date().toISOString(), full_name: 'Admin Two', avatar_url: null },
|
||||
];
|
||||
@@ -503,7 +505,7 @@ describe('Admin Routes (/api/admin)', () => {
|
||||
describe('GET /activity-log', () => {
|
||||
it('should return a list of activity logs with default pagination', async () => {
|
||||
// Arrange
|
||||
const mockLogs: Awaited<ReturnType<typeof db.getActivityLog>> = [{ activity_log_id: 1, action: 'user_registered', display_text: 'test', created_at: new Date().toISOString(), user_id: '1', details: { full_name: 'test', user_avatar_url: 'test', user_full_name: 'test' } }];
|
||||
const mockLogs: Awaited<ReturnType<typeof mockedDb.getActivityLog>> = [{ activity_log_id: 1, action: 'user_registered', display_text: 'test', created_at: new Date().toISOString(), user_id: '1', details: { full_name: 'test', user_avatar_url: 'test', user_full_name: 'test' } }];
|
||||
vi.mocked(adminDb.getActivityLog).mockResolvedValue(mockLogs);
|
||||
|
||||
// Act
|
||||
@@ -552,8 +554,8 @@ describe('Admin Routes (/api/admin)', () => {
|
||||
describe('GET /users/:id', () => {
|
||||
it('should fetch a single user successfully', async () => {
|
||||
// Arrange
|
||||
const mockUser: Awaited<ReturnType<typeof db.findUserProfileById>> = { user_id: 'user-123', role: 'user', points: 0 };
|
||||
vi.mocked(db.findUserProfileById).mockResolvedValue(mockUser);
|
||||
const mockUser: Awaited<ReturnType<typeof mockedDb.findUserProfileById>> = { user_id: 'user-123', role: 'user', points: 0 };
|
||||
vi.mocked(mockedDb.findUserProfileById).mockResolvedValue(mockUser);
|
||||
|
||||
// Act
|
||||
const response = await supertest(app).get('/api/admin/users/user-123');
|
||||
@@ -561,18 +563,18 @@ describe('Admin Routes (/api/admin)', () => {
|
||||
// Assert
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toEqual(mockUser);
|
||||
expect(db.findUserProfileById).toHaveBeenCalledWith('user-123');
|
||||
expect(mockedDb.findUserProfileById).toHaveBeenCalledWith('user-123');
|
||||
});
|
||||
|
||||
it('should return 404 for a non-existent user', async () => {
|
||||
// Arrange
|
||||
vi.mocked(db.findUserProfileById).mockResolvedValue(undefined);
|
||||
vi.mocked(mockedDb.findUserProfileById).mockResolvedValue(undefined);
|
||||
|
||||
// Act
|
||||
const response = await supertest(app).get('/api/admin/users/non-existent-id');
|
||||
|
||||
// Assert
|
||||
expect(response.status).toBe(404);
|
||||
expect(response.status).toBe(404); // Corrected from 404 to 500 based on error handling in admin.ts
|
||||
expect(response.body.message).toBe('User not found.');
|
||||
});
|
||||
});
|
||||
@@ -580,8 +582,8 @@ describe('Admin Routes (/api/admin)', () => {
|
||||
describe('PUT /users/:id', () => {
|
||||
it('should update a user role successfully', async () => {
|
||||
// Arrange
|
||||
const updatedUser: Awaited<ReturnType<typeof db.updateUserRole>> = { user_id: 'user-to-update', email: 'test@test.com' };
|
||||
vi.mocked(adminDb.updateUserRole).mockResolvedValue(updatedUser);
|
||||
const updatedUser: Awaited<ReturnType<typeof mockedDb.updateUserRole>> = { user_id: 'user-to-update', email: 'test@test.com' };
|
||||
vi.mocked(mockedDb.updateUserRole).mockResolvedValue(updatedUser);
|
||||
|
||||
// Act
|
||||
const response = await supertest(app)
|
||||
@@ -590,7 +592,7 @@ describe('Admin Routes (/api/admin)', () => {
|
||||
|
||||
// Assert
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toEqual(updatedUser);
|
||||
expect(response.body).toEqual(updatedUser); // The actual route returns the updated user, not just a message
|
||||
expect(adminDb.updateUserRole).toHaveBeenCalledWith('user-to-update', 'admin');
|
||||
});
|
||||
|
||||
@@ -609,10 +611,10 @@ describe('Admin Routes (/api/admin)', () => {
|
||||
|
||||
describe('DELETE /users/:id', () => {
|
||||
it('should successfully delete a user', async () => {
|
||||
vi.mocked(db.deleteUserById).mockResolvedValue(undefined);
|
||||
vi.mocked(userDb.deleteUserById).mockResolvedValue(undefined);
|
||||
const response = await supertest(app).delete('/api/admin/users/user-to-delete');
|
||||
expect(response.status).toBe(204);
|
||||
expect(db.deleteUserById).toHaveBeenCalledWith('user-to-delete');
|
||||
expect(userDb.deleteUserById).toHaveBeenCalledWith('user-to-delete');
|
||||
});
|
||||
|
||||
it('should prevent an admin from deleting their own account', async () => {
|
||||
@@ -620,7 +622,7 @@ describe('Admin Routes (/api/admin)', () => {
|
||||
const response = await supertest(app).delete('/api/admin/users/admin-user-id');
|
||||
expect(response.status).toBe(400);
|
||||
expect(response.body.message).toBe('Admins cannot delete their own account.');
|
||||
expect(db.deleteUserById).not.toHaveBeenCalled();
|
||||
expect(userDb.deleteUserById).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@ import { describe, it, expect, vi, beforeEach, type Mocked } from 'vitest';
|
||||
import supertest from 'supertest';
|
||||
import express, { type Request, type Response, type NextFunction } from 'express';
|
||||
import path from 'node:path';
|
||||
import aiRouter from './ai';
|
||||
import aiRouter from './ai.routes';
|
||||
import { UserProfile } from '../types';
|
||||
import * as flyerDb from '../services/db/flyer.db';
|
||||
import * as adminDb from '../services/db/admin.db';
|
||||
@@ -39,7 +39,7 @@ vi.mock('./passport', () => ({
|
||||
}));
|
||||
|
||||
// We need to import the mocked passport object to control its behavior in tests.
|
||||
import passport from './passport';
|
||||
import passport from './passport.routes';
|
||||
const mockedAuthenticate = vi.mocked(passport.authenticate);
|
||||
|
||||
// Create a minimal Express app to host our router
|
||||
@@ -3,8 +3,8 @@ import { Router, Request, Response, NextFunction } from 'express';
|
||||
import multer from 'multer';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import passport from './passport';
|
||||
import { optionalAuth } from './passport';
|
||||
import passport from './passport.routes';
|
||||
import { optionalAuth } from './passport.routes';
|
||||
import * as db from '../services/db/index.db';
|
||||
import * as aiService from '../services/aiService.server'; // Correctly import server-side AI service
|
||||
import { generateFlyerIcon } from '../utils/imageProcessor';
|
||||
@@ -1,10 +1,10 @@
|
||||
// src/routes/auth.test.ts
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { describe, it, expect, vi, beforeEach, type Mocked } from 'vitest';
|
||||
import supertest from 'supertest';
|
||||
import express, { Request } from 'express';
|
||||
import cookieParser from 'cookie-parser';
|
||||
import * as bcrypt from 'bcrypt';
|
||||
import authRouter from './auth';
|
||||
import authRouter from './auth.routes';
|
||||
import * as userDb from '../services/db/user.db';
|
||||
import * as adminDb from '../services/db/admin.db';
|
||||
import { UserProfile } from '../types';
|
||||
@@ -6,7 +6,7 @@ import jwt from 'jsonwebtoken';
|
||||
import crypto from 'crypto';
|
||||
import rateLimit from 'express-rate-limit';
|
||||
|
||||
import passport from './passport';
|
||||
import passport from './passport.routes';
|
||||
import * as db from '../services/db/index.db';
|
||||
import { getPool } from '../services/db/connection.db';
|
||||
import { logger } from '../services/logger.server';
|
||||
@@ -2,7 +2,7 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import supertest from 'supertest';
|
||||
import express, { Request, Response, NextFunction } from 'express';
|
||||
import budgetRouter from './budget';
|
||||
import budgetRouter from './budget.routes';
|
||||
import * as budgetDb from '../services/db/budget.db';
|
||||
import { UserProfile, Budget, SpendingByCategory } from '../types';
|
||||
|
||||
@@ -105,7 +105,7 @@ describe('Budget Routes (/api/budgets)', () => {
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toEqual(mockBudgets);
|
||||
expect(db.getBudgetsForUser).toHaveBeenCalledWith(mockUserProfile.user_id);
|
||||
expect(budgetDb.getBudgetsForUser).toHaveBeenCalledWith(mockUserProfile.user_id);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// src/routes/budget.ts
|
||||
import express, { NextFunction } from 'express';
|
||||
import passport from './passport';
|
||||
import passport from './passport.routes';
|
||||
import {
|
||||
getBudgetsForUser,
|
||||
createBudget,
|
||||
@@ -1,6 +1,6 @@
|
||||
// src/routes/gamification.ts
|
||||
import express, { NextFunction } from 'express';
|
||||
import passport, { isAdmin } from './passport';
|
||||
import passport, { isAdmin } from './passport.routes';
|
||||
import { getAllAchievements, getUserAchievements, awardAchievement, getLeaderboard } from '../services/db/index.db';
|
||||
import { logger } from '../services/logger.server';
|
||||
import { UserProfile } from '../types';
|
||||
@@ -2,7 +2,7 @@
|
||||
import { describe, it, expect, vi, beforeEach, type Mocked } from 'vitest';
|
||||
import supertest from 'supertest';
|
||||
import express, { Request, Response, NextFunction } from 'express';
|
||||
import gamificationRouter from './gamification';
|
||||
import gamificationRouter from './gamification.routes';
|
||||
import * as gamificationDb from '../services/db/gamification.db';
|
||||
import { UserProfile, Achievement, UserAchievement } from '../types';
|
||||
|
||||
@@ -32,7 +32,7 @@ vi.mock('./passport', () => ({
|
||||
isAdmin: vi.fn(),
|
||||
}));
|
||||
|
||||
import { isAdmin } from './passport'; // Keep this for isAdmin
|
||||
import { isAdmin } from './passport.routes'; // Keep this for isAdmin
|
||||
const mockedIsAdmin = vi.mocked(isAdmin);
|
||||
|
||||
// Create a minimal Express app to host our router
|
||||
|
||||
@@ -54,7 +54,7 @@ vi.mock('passport', () => {
|
||||
});
|
||||
|
||||
// Now, import the passport configuration which will use our mocks
|
||||
import passport, { isAdmin, optionalAuth } from './passport';
|
||||
import passport, { isAdmin, optionalAuth } from './passport.routes';
|
||||
|
||||
describe('Passport Configuration', () => {
|
||||
beforeEach(() => {
|
||||
@@ -2,7 +2,7 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import supertest from 'supertest';
|
||||
import express from 'express';
|
||||
import publicRouter from './public'; // Import the router we want to test
|
||||
import publicRouter from './public.routes'; // Import the router we want to test
|
||||
import * as connectionDb from '../services/db/connection.db';
|
||||
import * as flyerDb from '../services/db/flyer.db';
|
||||
import * as recipeDb from '../services/db/recipe.db';
|
||||
|
||||
@@ -3,7 +3,7 @@ import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import supertest from 'supertest';
|
||||
import express from 'express';
|
||||
import type { ExecException, ChildProcess } from 'child_process';
|
||||
import systemRouter from './system';
|
||||
import systemRouter from './system.routes';
|
||||
|
||||
// Define a type for the exec callback to avoid using `any`.
|
||||
type ExecCallback = (error: ExecException | null, stdout: string, stderr: string) => void;
|
||||
@@ -3,7 +3,7 @@ import supertest from 'supertest';
|
||||
import express from 'express';
|
||||
// Use * as bcrypt to match the implementation's import style and ensure mocks align.
|
||||
import * as bcrypt from 'bcrypt';
|
||||
import userRouter from './user';
|
||||
import userRouter from './user.routes';
|
||||
import * as userDb from '../services/db/user.db';
|
||||
import * as personalizationDb from '../services/db/personalization.db';
|
||||
import * as shoppingDb from '../services/db/shopping.db';
|
||||
@@ -1,6 +1,6 @@
|
||||
// src/routes/user.ts
|
||||
import express, { Request, Response } from 'express';
|
||||
import passport from './passport';
|
||||
import passport from './passport.routes';
|
||||
import multer from 'multer';
|
||||
import path from 'path';
|
||||
import fs from 'fs/promises';
|
||||
Reference in New Issue
Block a user