import { describe, it, expect, vi, beforeEach } from 'vitest'; import { NutritionTargetRepository } from './nutrition-target.repository.js'; const { mockSave, MockTargetModel } = vi.hoisted(() => { const mockSave = vi.fn(); function MockModel(this: { save: typeof mockSave }, data: unknown) { Object.assign(this, data); this.save = mockSave; } Object.assign(MockModel, { findOne: vi.fn(), find: vi.fn(), findOneAndUpdate: vi.fn(), updateMany: vi.fn(), }); return { mockSave, MockTargetModel: MockModel }; }); vi.mock('../../schemas/nutrition-target.schema.js', () => ({ NutritionTargetModel: MockTargetModel, })); const { NutritionTargetModel } = await import('../../schemas/nutrition-target.schema.js'); function makeChain(result: unknown = null) { return { sort: vi.fn().mockReturnThis(), lean: vi.fn().mockReturnThis(), exec: vi.fn().mockResolvedValue(result), }; } describe(NutritionTargetRepository.name, () => { let repo: NutritionTargetRepository; beforeEach(() => { vi.clearAllMocks(); repo = new NutritionTargetRepository(); }); describe('findByUser', () => { it('queries by userId, householdId, and isActive: true', async () => { const mockTarget = { _id: 't1', dailyCalories: 2000 }; vi.mocked(NutritionTargetModel.findOne).mockReturnValue(makeChain(mockTarget) as never); const result = await repo.findByUser('user1', 'hh1'); expect(NutritionTargetModel.findOne).toHaveBeenCalledWith({ userId: 'user1', householdId: 'hh1', isActive: true, }); expect(result).toEqual(mockTarget); }); }); describe('findAllByUser', () => { it('returns all targets sorted by newest first', async () => { const chain = makeChain([]); vi.mocked(NutritionTargetModel.find).mockReturnValue(chain as never); await repo.findAllByUser('user1', 'hh1'); expect(NutritionTargetModel.find).toHaveBeenCalledWith({ userId: 'user1', householdId: 'hh1', }); expect(chain.sort).toHaveBeenCalledWith({ createdAt: -1 }); }); }); describe('create', () => { it('saves and returns new document', async () => { const plainDoc = { _id: 'new-id', dailyCalories: 2000 }; mockSave.mockResolvedValue({ toObject: () => plainDoc }); const result = await repo.create({ dailyCalories: 2000 }); expect(mockSave).toHaveBeenCalled(); expect(result).toEqual(plainDoc); }); }); describe('deactivateAllForUser', () => { it('updates all active targets for the user to inactive', async () => { vi.mocked(NutritionTargetModel.updateMany).mockReturnValue({ exec: vi.fn().mockResolvedValue({ modifiedCount: 1 }), } as never); await repo.deactivateAllForUser('user1', 'hh1'); expect(NutritionTargetModel.updateMany).toHaveBeenCalledWith( { userId: 'user1', householdId: 'hh1', isActive: true }, { $set: { isActive: false } }, ); }); }); describe('update', () => { it('updates specific target using findOneAndUpdate', async () => { const updatedDoc = { _id: 't1', dailyCalories: 2100 }; vi.mocked(NutritionTargetModel.findOneAndUpdate).mockReturnValue(makeChain(updatedDoc) as never); const result = await repo.update('t1', 'user1', 'hh1', { dailyCalories: 2100 }); expect(NutritionTargetModel.findOneAndUpdate).toHaveBeenCalledWith( { _id: 't1', userId: 'user1', householdId: 'hh1' }, { $set: { dailyCalories: 2100 } }, { new: true, lean: true } ); expect(result).toEqual(updatedDoc); }); }); });