routes
All checks were successful
Deploy to Web Server flyer-crawler.projectium.com / deploy (push) Successful in 4m28s
All checks were successful
Deploy to Web Server flyer-crawler.projectium.com / deploy (push) Successful in 4m28s
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterAll, type Mocked, type Mock } from 'vitest';
|
||||
import supertest from 'supertest';
|
||||
import express, { Request, Response, NextFunction } from 'express';
|
||||
import path from 'node:path';
|
||||
import path from 'path';
|
||||
import fs from 'node:fs/promises';
|
||||
import adminRouter from './admin.routes'; // Correctly imported
|
||||
import { UserProfile } from '../types';
|
||||
@@ -31,32 +31,25 @@ vi.mock('../services/logger.server', () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
/**
|
||||
* Mock the passport authentication middleware.
|
||||
* This is the core of testing protected routes. We replace the real authentication
|
||||
* with a flexible mock that we can control in each test.
|
||||
*/
|
||||
// Use vi.hoisted to create a mutable mock function reference that can be controlled in tests.
|
||||
const mockedIsAdmin = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock('./passport', () => ({
|
||||
// Mock the default export (the passport instance)
|
||||
default: {
|
||||
// The 'authenticate' method returns a middleware function. We mock that.
|
||||
authenticate: vi.fn(() => (req: Request, res: Response, next: NextFunction) => {
|
||||
// This mock will be controlled by the isAdmin mock, but we ensure it calls next()
|
||||
// to allow the isAdmin middleware to run.
|
||||
// For admin tests, we just need to ensure the request passes through to the isAdmin middleware.
|
||||
next();
|
||||
}),
|
||||
},
|
||||
// Mock the named export 'isAdmin'
|
||||
isAdmin: vi.fn((_req: Request, res: Response) => {
|
||||
// The default behavior of this mock is to deny access.
|
||||
// We will override this implementation in specific tests.
|
||||
res.status(401).json({ message: 'Unauthorized' });
|
||||
}),
|
||||
// Mock the named export 'isAdmin' by assigning our hoisted mock function to it.
|
||||
isAdmin: mockedIsAdmin,
|
||||
}));
|
||||
|
||||
// We need to import the mocked 'isAdmin' so we can change its behavior in tests.
|
||||
import { isAdmin } from './passport.routes';
|
||||
const mockedIsAdmin = isAdmin as Mock;
|
||||
// We no longer need to import `isAdmin` from the real module, as we control `mockedIsAdmin` directly.
|
||||
// import { isAdmin } from './passport.routes'; // This line is removed.
|
||||
// const mockedIsAdmin = isAdmin as Mock; // This line is removed.
|
||||
|
||||
// Create a minimal Express app to host our router
|
||||
const app = express();
|
||||
|
||||
@@ -26,22 +26,19 @@ vi.mock('../services/logger.server', () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
// Use vi.hoisted to create a mutable mock function reference for the authenticate middleware.
|
||||
const mockedAuthenticate = vi.hoisted(() => vi.fn((_req: Request, _res: Response, next: NextFunction) => next()));
|
||||
|
||||
// Mock the passport module to control authentication for different tests.
|
||||
vi.mock('./passport', () => ({
|
||||
// Mock the default export for passport.authenticate
|
||||
default: {
|
||||
authenticate: vi.fn(() => (_req: Request, _res: Response, next: NextFunction) => {
|
||||
next(); // Immediately pass through for testing purposes
|
||||
}),
|
||||
authenticate: mockedAuthenticate,
|
||||
},
|
||||
// Mock the named export for optionalAuth
|
||||
optionalAuth: vi.fn((req, res, next) => next()),
|
||||
}));
|
||||
|
||||
// We need to import the mocked passport object to control its behavior in tests.
|
||||
import passport from './passport.routes';
|
||||
const mockedAuthenticate = vi.mocked(passport.authenticate);
|
||||
|
||||
// Create a minimal Express app to host our router
|
||||
const app = express();
|
||||
app.use(express.json({ strict: false }));
|
||||
@@ -51,11 +48,13 @@ describe('AI Routes (/api/ai)', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
// Default mock for passport.authenticate to simulate an unauthenticated request.
|
||||
// This will be overridden in tests that require an authenticated user.
|
||||
mockedAuthenticate.mockImplementation(
|
||||
() => (req: Request, res: Response) => {
|
||||
// We use mockImplementation to return a function that returns the middleware.
|
||||
// This correctly mimics passport.authenticate('jwt', options) returning a middleware function.
|
||||
mockedAuthenticate.mockImplementation(() => {
|
||||
return (req: Request, res: Response) => {
|
||||
res.status(401).json({ message: 'Unauthorized' });
|
||||
});
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST /flyers/process', () => {
|
||||
@@ -201,12 +200,12 @@ describe('AI Routes (/api/ai)', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
// For this block, simulate a logged-in user by having the middleware call next().
|
||||
mockedAuthenticate.mockImplementation(
|
||||
() => (req: Request, res: Response, next: NextFunction) => {
|
||||
mockedAuthenticate.mockImplementation(() => {
|
||||
return (req: Request, res: Response, next: NextFunction) => {
|
||||
req.user = mockUserProfile;
|
||||
next();
|
||||
}
|
||||
);
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
it('POST /quick-insights should return the stubbed response', async () => {
|
||||
|
||||
@@ -20,21 +20,19 @@ vi.mock('../services/logger.server', () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
// Mock the passport authentication middleware
|
||||
let mockAuthMiddleware = (req: Request, res: Response, next: NextFunction) => next();
|
||||
// Use vi.hoisted to create mutable mock function references.
|
||||
const mockedAuthMiddleware = vi.hoisted(() => vi.fn((req: Request, res: Response, next: NextFunction) => next()));
|
||||
const mockedIsAdmin = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock('./passport', () => ({
|
||||
default: {
|
||||
authenticate: vi.fn(() => (req: Request, res: Response, next: NextFunction) => {
|
||||
mockAuthMiddleware(req, res, next);
|
||||
}),
|
||||
// The authenticate method will now call our hoisted mock middleware.
|
||||
authenticate: vi.fn(() => mockedAuthMiddleware),
|
||||
},
|
||||
// Mock the named export 'isAdmin'
|
||||
isAdmin: vi.fn(),
|
||||
isAdmin: mockedIsAdmin,
|
||||
}));
|
||||
|
||||
import { isAdmin } from './passport.routes'; // Keep this for isAdmin
|
||||
const mockedIsAdmin = vi.mocked(isAdmin);
|
||||
|
||||
// Create a minimal Express app to host our router
|
||||
const app = express();
|
||||
app.use(express.json({ strict: false }));
|
||||
@@ -56,10 +54,10 @@ describe('Gamification Routes (/api/achievements)', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
// Default mock for unauthenticated user for protected routes
|
||||
mockAuthMiddleware = (req: Request, res: Response) => {
|
||||
// Default mock for authentication to simulate an unauthenticated user.
|
||||
mockedAuthMiddleware.mockImplementation((req: Request, res: Response) => {
|
||||
res.status(401).json({ message: 'Unauthorized' });
|
||||
};
|
||||
});
|
||||
mockedIsAdmin.mockImplementation((req: Request, res: Response) => {
|
||||
res.status(403).json({ message: 'Forbidden' });
|
||||
});
|
||||
@@ -88,11 +86,11 @@ describe('Gamification Routes (/api/achievements)', () => {
|
||||
});
|
||||
|
||||
it('should return achievements for the authenticated user', async () => {
|
||||
// Mock for authenticated user
|
||||
mockAuthMiddleware = (req: Request, res: Response, next: NextFunction) => {
|
||||
// Mock authentication to simulate a logged-in user.
|
||||
mockedAuthMiddleware.mockImplementation((req: Request, res: Response, next: NextFunction) => {
|
||||
req.user = mockUserProfile;
|
||||
next();
|
||||
};
|
||||
});
|
||||
|
||||
const mockUserAchievements: (UserAchievement & Achievement)[] = [{ achievement_id: 1, user_id: 'user-123', achieved_at: '2024-01-01', name: 'First Steps', description: '...', icon: 'footprints', points_value: 10 }];
|
||||
mockedDb.getUserAchievements.mockResolvedValue(mockUserAchievements);
|
||||
@@ -115,11 +113,11 @@ describe('Gamification Routes (/api/achievements)', () => {
|
||||
|
||||
it('should return 403 Forbidden if authenticated user is not an admin', async () => {
|
||||
// Mock a regular authenticated user
|
||||
mockAuthMiddleware = (req: Request, res: Response, next: NextFunction) => {
|
||||
mockedAuthMiddleware.mockImplementation((req: Request, res: Response, next: NextFunction) => {
|
||||
req.user = mockUserProfile;
|
||||
next();
|
||||
};
|
||||
// Let the default isAdmin mock run, which denies access
|
||||
});
|
||||
// Let the default isAdmin mock (set in beforeEach) run, which denies access
|
||||
|
||||
const response = await supertest(app).post('/api/achievements/award').send(awardPayload);
|
||||
expect(response.status).toBe(403);
|
||||
@@ -127,11 +125,11 @@ describe('Gamification Routes (/api/achievements)', () => {
|
||||
|
||||
it('should successfully award an achievement when user is an admin', async () => {
|
||||
// Mock an authenticated admin user
|
||||
mockAuthMiddleware = (req: Request, res: Response, next: NextFunction) => {
|
||||
mockedAuthMiddleware.mockImplementation((req: Request, res: Response, next: NextFunction) => {
|
||||
req.user = mockAdminProfile;
|
||||
next();
|
||||
};
|
||||
mockedIsAdmin.mockImplementation((req: Request, res: Response, next: NextFunction) => next());
|
||||
});
|
||||
mockedIsAdmin.mockImplementation((req: Request, res: Response, next: NextFunction) => next()); // Grant admin access
|
||||
mockedDb.awardAchievement.mockResolvedValue(undefined);
|
||||
|
||||
const response = await supertest(app).post('/api/achievements/award').send(awardPayload);
|
||||
|
||||
@@ -36,14 +36,13 @@ vi.mock('../services/logger.server', () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
// Mock Passport middleware
|
||||
let mockAuthMiddleware = (req: express.Request, res: express.Response, next: express.NextFunction) => next();
|
||||
// Use vi.hoisted to create a mutable mock function reference for the authenticate middleware.
|
||||
const mockedAuthMiddleware = vi.hoisted(() => vi.fn((req: express.Request, res: express.Response, next: express.NextFunction) => next()));
|
||||
|
||||
// Mock Passport middleware
|
||||
vi.mock('./passport', () => ({
|
||||
default: {
|
||||
authenticate: vi.fn(() => (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||
mockAuthMiddleware(req, res, next);
|
||||
}),
|
||||
authenticate: vi.fn(() => mockedAuthMiddleware),
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -56,10 +55,10 @@ describe('User Routes (/api/users)', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
|
||||
// Default authentication state: Unauthorized
|
||||
mockAuthMiddleware = (req: express.Request, res: express.Response) => {
|
||||
// Default authentication state: Unauthorized by default for each test.
|
||||
mockedAuthMiddleware.mockImplementation((req: express.Request, res: express.Response) => {
|
||||
res.status(401).json({ message: 'Unauthorized' });
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
describe('when user is not authenticated', () => {
|
||||
@@ -86,11 +85,11 @@ describe('User Routes (/api/users)', () => {
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
// Simulate logged-in user
|
||||
mockAuthMiddleware = (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||
// Simulate a logged-in user for this block of tests.
|
||||
mockedAuthMiddleware.mockImplementation((req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||
req.user = mockUserProfile;
|
||||
next();
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET /profile', () => {
|
||||
|
||||
Reference in New Issue
Block a user