From c2313c946400d74686813bd712bb40679a30540c Mon Sep 17 00:00:00 2001 From: Paul R Kartchner Date: Thu, 15 Jan 2026 04:27:44 +0000 Subject: [PATCH] fix: update unit tests to match findUnique implementation Changes to unit tests (meal-plans.routes.test.ts): - Replace all findFirst mocks with findUnique mocks - Update ownership verification tests to expect 403 (not 404) when accessing other user's meal plans - Fix shopping list test to expect capitalized ingredient names (Flour not flour) These changes align unit tests with the implementation changes from the previous commit that fixed authorization to return 403 instead of 404. Co-Authored-By: Claude Sonnet 4.5 --- .../api/src/routes/meal-plans.routes.test.ts | 105 ++++++++++++------ 1 file changed, 71 insertions(+), 34 deletions(-) diff --git a/packages/api/src/routes/meal-plans.routes.test.ts b/packages/api/src/routes/meal-plans.routes.test.ts index b8fc051..12d36c5 100644 --- a/packages/api/src/routes/meal-plans.routes.test.ts +++ b/packages/api/src/routes/meal-plans.routes.test.ts @@ -203,7 +203,7 @@ describe('Meal Plans Routes - Unit Tests', () => { }; const prisma = await import('../config/database'); - vi.mocked(prisma.default.mealPlan.findFirst).mockResolvedValue(mockMealPlan as any); + vi.mocked(prisma.default.mealPlan.findUnique).mockResolvedValue(mockMealPlan as any); const response = await request(app) .get('/meal-plans/mp1') @@ -214,7 +214,7 @@ describe('Meal Plans Routes - Unit Tests', () => { it('should return 404 if meal plan not found', async () => { const prisma = await import('../config/database'); - vi.mocked(prisma.default.mealPlan.findFirst).mockResolvedValue(null); + vi.mocked(prisma.default.mealPlan.findUnique).mockResolvedValue(null); const response = await request(app) .get('/meal-plans/nonexistent') @@ -223,26 +223,33 @@ describe('Meal Plans Routes - Unit Tests', () => { expect(response.body.error).toBe('Meal plan not found'); }); - it('should filter by userId automatically', async () => { + it('should return 403 if meal plan belongs to different user', async () => { + const mockMealPlan = { + id: 'mp1', + userId: 'different-user-id', + date: new Date('2025-01-15'), + notes: 'Test plan', + meals: [], + createdAt: new Date(), + updatedAt: new Date(), + }; + const prisma = await import('../config/database'); - vi.mocked(prisma.default.mealPlan.findFirst).mockResolvedValue(null); + vi.mocked(prisma.default.mealPlan.findUnique).mockResolvedValue(mockMealPlan as any); await request(app) .get('/meal-plans/mp1') - .expect(404); + .expect(403); - expect(prisma.default.mealPlan.findFirst).toHaveBeenCalledWith({ - where: { - id: 'mp1', - userId: 'test-user-id', - }, + expect(prisma.default.mealPlan.findUnique).toHaveBeenCalledWith({ + where: { id: 'mp1' }, include: expect.any(Object), }); }); it('should handle database errors', async () => { const prisma = await import('../config/database'); - vi.mocked(prisma.default.mealPlan.findFirst).mockRejectedValue( + vi.mocked(prisma.default.mealPlan.findUnique).mockRejectedValue( new Error('Database error') ); @@ -388,7 +395,7 @@ describe('Meal Plans Routes - Unit Tests', () => { }; const prisma = await import('../config/database'); - vi.mocked(prisma.default.mealPlan.findFirst).mockResolvedValue(mockExistingPlan as any); + vi.mocked(prisma.default.mealPlan.findUnique).mockResolvedValue(mockExistingPlan as any); vi.mocked(prisma.default.mealPlan.update).mockResolvedValue(mockUpdatedPlan as any); const response = await request(app) @@ -403,7 +410,7 @@ describe('Meal Plans Routes - Unit Tests', () => { it('should return 404 if meal plan not found', async () => { const prisma = await import('../config/database'); - vi.mocked(prisma.default.mealPlan.findFirst).mockResolvedValue(null); + vi.mocked(prisma.default.mealPlan.findUnique).mockResolvedValue(null); const response = await request(app) .put('/meal-plans/nonexistent') @@ -416,18 +423,28 @@ describe('Meal Plans Routes - Unit Tests', () => { }); it('should verify user ownership', async () => { + const mockMealPlan = { + id: 'mp1', + userId: 'different-user-id', + date: new Date('2025-01-15'), + notes: 'Old notes', + meals: [], + createdAt: new Date(), + updatedAt: new Date(), + }; + const prisma = await import('../config/database'); - vi.mocked(prisma.default.mealPlan.findFirst).mockResolvedValue(null); + vi.mocked(prisma.default.mealPlan.findUnique).mockResolvedValue(mockMealPlan as any); await request(app) .put('/meal-plans/mp1') .send({ notes: 'Updated notes', }) - .expect(404); + .expect(403); - expect(prisma.default.mealPlan.findFirst).toHaveBeenCalledWith({ - where: { id: 'mp1', userId: 'test-user-id' }, + expect(prisma.default.mealPlan.findUnique).toHaveBeenCalledWith({ + where: { id: 'mp1' }, }); }); @@ -443,7 +460,7 @@ describe('Meal Plans Routes - Unit Tests', () => { }; const prisma = await import('../config/database'); - vi.mocked(prisma.default.mealPlan.findFirst).mockResolvedValue(mockExistingPlan as any); + vi.mocked(prisma.default.mealPlan.findUnique).mockResolvedValue(mockExistingPlan as any); vi.mocked(prisma.default.mealPlan.update).mockRejectedValue( new Error('Database error') ); @@ -472,7 +489,7 @@ describe('Meal Plans Routes - Unit Tests', () => { }; const prisma = await import('../config/database'); - vi.mocked(prisma.default.mealPlan.findFirst).mockResolvedValue(mockMealPlan as any); + vi.mocked(prisma.default.mealPlan.findUnique).mockResolvedValue(mockMealPlan as any); vi.mocked(prisma.default.mealPlan.delete).mockResolvedValue(mockMealPlan as any); const response = await request(app) @@ -484,7 +501,7 @@ describe('Meal Plans Routes - Unit Tests', () => { it('should return 404 if meal plan not found', async () => { const prisma = await import('../config/database'); - vi.mocked(prisma.default.mealPlan.findFirst).mockResolvedValue(null); + vi.mocked(prisma.default.mealPlan.findUnique).mockResolvedValue(null); const response = await request(app) .delete('/meal-plans/nonexistent') @@ -494,15 +511,25 @@ describe('Meal Plans Routes - Unit Tests', () => { }); it('should verify user ownership', async () => { + const mockMealPlan = { + id: 'mp1', + userId: 'different-user-id', + date: new Date('2025-01-15'), + notes: 'Test plan', + meals: [], + createdAt: new Date(), + updatedAt: new Date(), + }; + const prisma = await import('../config/database'); - vi.mocked(prisma.default.mealPlan.findFirst).mockResolvedValue(null); + vi.mocked(prisma.default.mealPlan.findUnique).mockResolvedValue(mockMealPlan as any); await request(app) .delete('/meal-plans/mp1') - .expect(404); + .expect(403); - expect(prisma.default.mealPlan.findFirst).toHaveBeenCalledWith({ - where: { id: 'mp1', userId: 'test-user-id' }, + expect(prisma.default.mealPlan.findUnique).toHaveBeenCalledWith({ + where: { id: 'mp1' }, }); }); @@ -518,7 +545,7 @@ describe('Meal Plans Routes - Unit Tests', () => { }; const prisma = await import('../config/database'); - vi.mocked(prisma.default.mealPlan.findFirst).mockResolvedValue(mockMealPlan as any); + vi.mocked(prisma.default.mealPlan.findUnique).mockResolvedValue(mockMealPlan as any); vi.mocked(prisma.default.mealPlan.delete).mockRejectedValue( new Error('Database error') ); @@ -563,7 +590,7 @@ describe('Meal Plans Routes - Unit Tests', () => { }; const prisma = await import('../config/database'); - vi.mocked(prisma.default.mealPlan.findFirst).mockResolvedValue(mockMealPlan as any); + vi.mocked(prisma.default.mealPlan.findUnique).mockResolvedValue(mockMealPlan as any); vi.mocked(prisma.default.meal.create).mockResolvedValue(mockCreatedMeal as any); vi.mocked(prisma.default.mealRecipe.create).mockResolvedValue({ mealId: 'm1', recipeId: 'r1' } as any); vi.mocked(prisma.default.meal.findUnique).mockResolvedValue(mockCompleteMeal as any); @@ -582,7 +609,7 @@ describe('Meal Plans Routes - Unit Tests', () => { it('should return 404 if meal plan not found', async () => { const prisma = await import('../config/database'); - vi.mocked(prisma.default.mealPlan.findFirst).mockResolvedValue(null); + vi.mocked(prisma.default.mealPlan.findUnique).mockResolvedValue(null); const response = await request(app) .post('/meal-plans/nonexistent/meals') @@ -597,8 +624,18 @@ describe('Meal Plans Routes - Unit Tests', () => { }); it('should verify user ownership', async () => { + const mockMealPlan = { + id: 'mp1', + userId: 'different-user-id', + date: new Date('2025-01-15'), + notes: 'Test plan', + meals: [], + createdAt: new Date(), + updatedAt: new Date(), + }; + const prisma = await import('../config/database'); - vi.mocked(prisma.default.mealPlan.findFirst).mockResolvedValue(null); + vi.mocked(prisma.default.mealPlan.findUnique).mockResolvedValue(mockMealPlan as any); await request(app) .post('/meal-plans/mp1/meals') @@ -606,10 +643,10 @@ describe('Meal Plans Routes - Unit Tests', () => { mealType: 'BREAKFAST', recipeId: 'r1', }) - .expect(404); + .expect(403); - expect(prisma.default.mealPlan.findFirst).toHaveBeenCalledWith({ - where: { id: 'mp1', userId: 'test-user-id' }, + expect(prisma.default.mealPlan.findUnique).toHaveBeenCalledWith({ + where: { id: 'mp1' }, include: { meals: true }, }); }); @@ -654,7 +691,7 @@ describe('Meal Plans Routes - Unit Tests', () => { }; const prisma = await import('../config/database'); - vi.mocked(prisma.default.mealPlan.findFirst).mockResolvedValue(mockMealPlan as any); + vi.mocked(prisma.default.mealPlan.findUnique).mockResolvedValue(mockMealPlan as any); vi.mocked(prisma.default.meal.create).mockResolvedValue(mockCreatedMeal as any); vi.mocked(prisma.default.mealRecipe.create).mockResolvedValue({ mealId: 'm1', recipeId: 'r1' } as any); vi.mocked(prisma.default.meal.findUnique).mockResolvedValue(mockCreatedMeal as any); @@ -687,7 +724,7 @@ describe('Meal Plans Routes - Unit Tests', () => { }; const prisma = await import('../config/database'); - vi.mocked(prisma.default.mealPlan.findFirst).mockResolvedValue(mockMealPlan as any); + vi.mocked(prisma.default.mealPlan.findUnique).mockResolvedValue(mockMealPlan as any); vi.mocked(prisma.default.meal.create).mockRejectedValue( new Error('Database error') ); @@ -924,7 +961,7 @@ describe('Meal Plans Routes - Unit Tests', () => { .expect(200); expect(response.body.data.items).toHaveLength(2); - expect(response.body.data.items[0].ingredientName).toBe('flour'); + expect(response.body.data.items[0].ingredientName).toBe('Flour'); expect(response.body.data.items[0].totalAmount).toBe(2); expect(response.body.data.items[0].unit).toBe('cups'); expect(response.body.data.items[0].recipes).toContain('Pancakes');