diff --git a/src/routes/admin.content.routes.test.ts b/src/routes/admin.content.routes.test.ts index ea5d764c..7b02224c 100644 --- a/src/routes/admin.content.routes.test.ts +++ b/src/routes/admin.content.routes.test.ts @@ -116,6 +116,12 @@ describe('Admin Content Management Routes (/api/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 }); + // Add a basic error handler to capture errors passed to next(err) and return JSON. + // This prevents unhandled error crashes in tests and ensures we get the 500 response we expect. + app.use((err: any, req: any, res: any, next: any) => { + res.status(err.status || 500).json({ message: err.message, errors: err.errors }); + }); + beforeEach(() => { vi.clearAllMocks(); }); diff --git a/src/routes/admin.jobs.routes.test.ts b/src/routes/admin.jobs.routes.test.ts index eb6b218c..bf7f56fe 100644 --- a/src/routes/admin.jobs.routes.test.ts +++ b/src/routes/admin.jobs.routes.test.ts @@ -92,6 +92,12 @@ describe('Admin Job Trigger Routes (/api/admin/trigger)', () => { // 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 }); + // Add a basic error handler to capture errors passed to next(err) and return JSON. + // This prevents unhandled error crashes in tests and ensures we get the 500 response we expect. + app.use((err: any, req: any, res: any, next: any) => { + res.status(err.status || 500).json({ message: err.message, errors: err.errors }); + }); + beforeEach(() => { vi.clearAllMocks(); }); diff --git a/src/routes/admin.monitoring.routes.test.ts b/src/routes/admin.monitoring.routes.test.ts index 12d3735b..bb905146 100644 --- a/src/routes/admin.monitoring.routes.test.ts +++ b/src/routes/admin.monitoring.routes.test.ts @@ -102,6 +102,12 @@ describe('Admin Monitoring Routes (/api/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 }); + // Add a basic error handler to capture errors passed to next(err) and return JSON. + // This prevents unhandled error crashes in tests and ensures we get the 500 response we expect. + app.use((err: any, req: any, res: any, next: any) => { + res.status(err.status || 500).json({ message: err.message, errors: err.errors }); + }); + beforeEach(() => { vi.clearAllMocks(); }); diff --git a/src/routes/admin.stats.routes.test.ts b/src/routes/admin.stats.routes.test.ts index aa955466..43507dbf 100644 --- a/src/routes/admin.stats.routes.test.ts +++ b/src/routes/admin.stats.routes.test.ts @@ -74,6 +74,12 @@ describe('Admin Stats Routes (/api/admin/stats)', () => { // 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 }); + // Add a basic error handler to capture errors passed to next(err) and return JSON. + // This prevents unhandled error crashes in tests and ensures we get the 500 response we expect. + app.use((err: any, req: any, res: any, next: any) => { + res.status(err.status || 500).json({ message: err.message, errors: err.errors }); + }); + beforeEach(() => { vi.clearAllMocks(); }); diff --git a/src/routes/admin.system.routes.test.ts b/src/routes/admin.system.routes.test.ts index 22483678..56c06917 100644 --- a/src/routes/admin.system.routes.test.ts +++ b/src/routes/admin.system.routes.test.ts @@ -64,6 +64,12 @@ describe('Admin System Routes (/api/admin/system)', () => { const adminUser = createMockUserProfile({ role: 'admin' }); const app = createTestApp({ router: adminRouter, basePath: '/api/admin', authenticatedUser: adminUser }); + // Add a basic error handler to capture errors passed to next(err) and return JSON. + // This prevents unhandled error crashes in tests and ensures we get the 500 response we expect. + app.use((err: any, req: any, res: any, next: any) => { + res.status(err.status || 500).json({ message: err.message, errors: err.errors }); + }); + beforeEach(() => { vi.clearAllMocks(); }); diff --git a/src/routes/admin.users.routes.test.ts b/src/routes/admin.users.routes.test.ts index b3406b72..1b0754cf 100644 --- a/src/routes/admin.users.routes.test.ts +++ b/src/routes/admin.users.routes.test.ts @@ -81,6 +81,12 @@ describe('Admin User Management Routes (/api/admin/users)', () => { // 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 }); + // Add a basic error handler to capture errors passed to next(err) and return JSON. + // This prevents unhandled error crashes in tests and ensures we get the 500 response we expect. + app.use((err: any, req: any, res: any, next: any) => { + res.status(err.status || 500).json({ message: err.message, errors: err.errors }); + }); + beforeEach(() => { vi.clearAllMocks(); }); diff --git a/src/routes/ai.routes.test.ts b/src/routes/ai.routes.test.ts index 53f8fc8c..6f4fb782 100644 --- a/src/routes/ai.routes.test.ts +++ b/src/routes/ai.routes.test.ts @@ -76,6 +76,12 @@ describe('AI Routes (/api/ai)', () => { }); const app = createTestApp({ router: aiRouter, basePath: '/api/ai' }); + // Add a basic error handler to capture errors passed to next(err) and return JSON. + // This prevents unhandled error crashes in tests and ensures we get the 500 response we expect. + app.use((err: any, req: any, res: any, next: any) => { + res.status(err.status || 500).json({ message: err.message, errors: err.errors }); + }); + describe('POST /upload-and-process', () => { const imagePath = path.resolve(__dirname, '../tests/assets/test-flyer-image.jpg'); diff --git a/src/routes/budget.routes.test.ts b/src/routes/budget.routes.test.ts index d9997862..80bf4f93 100644 --- a/src/routes/budget.routes.test.ts +++ b/src/routes/budget.routes.test.ts @@ -63,6 +63,12 @@ describe('Budget Routes (/api/budgets)', () => { const app = createTestApp({ router: budgetRouter, basePath: '/api/budgets', authenticatedUser: mockUser }); + // Add a basic error handler to capture errors passed to next(err) and return JSON. + // This prevents unhandled error crashes in tests and ensures we get the 500 response we expect. + app.use((err: any, req: any, res: any, next: any) => { + res.status(err.status || 500).json({ message: err.message, errors: err.errors }); + }); + describe('GET /', () => { it('should return a list of budgets for the user', async () => { const mockBudgets = [createMockBudget({ budget_id: 1, user_id: 'user-123' })]; diff --git a/src/routes/deals.routes.test.ts b/src/routes/deals.routes.test.ts index b8bf4f8c..8708a36f 100644 --- a/src/routes/deals.routes.test.ts +++ b/src/routes/deals.routes.test.ts @@ -46,6 +46,13 @@ describe('Deals Routes (/api/users/deals)', () => { const basePath = '/api/users/deals'; const authenticatedApp = createTestApp({ router: dealsRouter, basePath, authenticatedUser: mockUser }); const unauthenticatedApp = createTestApp({ router: dealsRouter, basePath }); + const errorHandler = (err: any, req: any, res: any, next: any) => { + res.status(err.status || 500).json({ message: err.message, errors: err.errors }); + }; + + // Apply the handler to both app instances + authenticatedApp.use(errorHandler); + unauthenticatedApp.use(errorHandler); beforeEach(() => { vi.clearAllMocks(); @@ -67,5 +74,13 @@ describe('Deals Routes (/api/users/deals)', () => { expect(response.body).toEqual(mockDeals); expect(dealsRepo.findBestPricesForWatchedItems).toHaveBeenCalledWith(mockUser.user_id, expectLogger); }); + + it('should return 500 if the database call fails', async () => { + vi.mocked(dealsRepo.findBestPricesForWatchedItems).mockRejectedValue(new Error('DB Error')); + + const response = await supertest(authenticatedApp).get('/api/users/deals/best-watched-prices'); + expect(response.status).toBe(500); + expect(response.body.message).toBe('DB Error'); + }); }); }); \ No newline at end of file diff --git a/src/routes/flyer.routes.test.ts b/src/routes/flyer.routes.test.ts index 567015ed..3f49b75b 100644 --- a/src/routes/flyer.routes.test.ts +++ b/src/routes/flyer.routes.test.ts @@ -41,6 +41,12 @@ describe('Flyer Routes (/api/flyers)', () => { const app = createTestApp({ router: flyerRouter, basePath: '/api/flyers' }); + // Add a basic error handler to capture errors passed to next(err) and return JSON. + // This prevents unhandled error crashes in tests and ensures we get the 500 response we expect. + app.use((err: any, req: any, res: any, next: any) => { + res.status(err.status || 500).json({ message: err.message, errors: err.errors }); + }); + describe('GET /', () => { it('should return a list of flyers on success', async () => { const mockFlyers = [createMockFlyer({ flyer_id: 1 }), createMockFlyer({ flyer_id: 2 })]; diff --git a/src/routes/gamification.routes.test.ts b/src/routes/gamification.routes.test.ts index 5cb9db03..eebc9999 100644 --- a/src/routes/gamification.routes.test.ts +++ b/src/routes/gamification.routes.test.ts @@ -66,6 +66,12 @@ describe('Gamification Routes (/api/achievements)', () => { const unauthenticatedApp = createTestApp({ router: gamificationRouter, basePath }); const authenticatedApp = createTestApp({ router: gamificationRouter, basePath, authenticatedUser: mockUserProfile }); const adminApp = createTestApp({ router: gamificationRouter, basePath, authenticatedUser: mockAdminProfile }); + const errorHandler = (err: any, req: any, res: any, next: any) => { + res.status(err.status || 500).json({ message: err.message, errors: err.errors }); + }; + unauthenticatedApp.use(errorHandler); + authenticatedApp.use(errorHandler); + adminApp.use(errorHandler); describe('GET /', () => { it('should return a list of all achievements (public endpoint)', async () => { diff --git a/src/routes/personalization.routes.test.ts b/src/routes/personalization.routes.test.ts index 268886f0..efacb955 100644 --- a/src/routes/personalization.routes.test.ts +++ b/src/routes/personalization.routes.test.ts @@ -25,6 +25,13 @@ import * as db from '../services/db/index.db'; describe('Personalization Routes (/api/personalization)', () => { const app = createTestApp({ router: personalizationRouter, basePath: '/api/personalization' }); + + // Add a basic error handler to capture errors passed to next(err) and return JSON. + // This prevents unhandled error crashes in tests and ensures we get the 500 response we expect. + app.use((err: any, req: any, res: any, next: any) => { + res.status(err.status || 500).json({ message: err.message, errors: err.errors }); + }); + beforeEach(() => { vi.clearAllMocks(); }); diff --git a/src/routes/recipe.routes.test.ts b/src/routes/recipe.routes.test.ts index c52524b7..0ef38261 100644 --- a/src/routes/recipe.routes.test.ts +++ b/src/routes/recipe.routes.test.ts @@ -33,6 +33,13 @@ const expectLogger = expect.objectContaining({ describe('Recipe Routes (/api/recipes)', () => { const app = createTestApp({ router: recipeRouter, basePath: '/api/recipes' }); + + // Add a basic error handler to capture errors passed to next(err) and return JSON. + // This prevents unhandled error crashes in tests and ensures we get the 500 response we expect. + app.use((err: any, req: any, res: any, next: any) => { + res.status(err.status || 500).json({ message: err.message, errors: err.errors }); + }); + beforeEach(() => { vi.clearAllMocks(); }); diff --git a/src/routes/stats.routes.test.ts b/src/routes/stats.routes.test.ts index b278e656..9d9ad9c6 100644 --- a/src/routes/stats.routes.test.ts +++ b/src/routes/stats.routes.test.ts @@ -27,6 +27,13 @@ const expectLogger = expect.objectContaining({ describe('Stats Routes (/api/stats)', () => { const app = createTestApp({ router: statsRouter, basePath: '/api/stats' }); + + // Add a basic error handler to capture errors passed to next(err) and return JSON. + // This prevents unhandled error crashes in tests and ensures we get the 500 response we expect. + app.use((err: any, req: any, res: any, next: any) => { + res.status(err.status || 500).json({ message: err.message, errors: err.errors }); + }); + beforeEach(() => { vi.clearAllMocks(); }); diff --git a/src/routes/user.routes.test.ts b/src/routes/user.routes.test.ts index 28834ecb..eaed8731 100644 --- a/src/routes/user.routes.test.ts +++ b/src/routes/user.routes.test.ts @@ -130,6 +130,12 @@ describe('User Routes (/api/users)', () => { const mockUserProfile = createMockUserProfile({ user_id: 'user-123' }); const app = createTestApp({ router: userRouter, basePath, authenticatedUser: mockUserProfile }); + // Add a basic error handler to capture errors passed to next(err) and return JSON. + // This prevents unhandled error crashes in tests and ensures we get the 500 response we expect. + app.use((err: any, req: any, res: any, next: any) => { + res.status(err.status || 500).json({ message: err.message, errors: err.errors }); + }); + beforeEach(() => { // All tests in this block will use the authenticated app });