2026-05-14 18:38:50 +09:00
|
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
2026-05-19 11:06:03 +09:00
|
|
|
import { NutritionTargetRepository } from '../../../src/modules/nutrition-targets/nutrition-target.repository.js';
|
2026-05-14 18:38:50 +09:00
|
|
|
|
|
|
|
|
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 };
|
|
|
|
|
});
|
|
|
|
|
|
2026-05-19 11:06:03 +09:00
|
|
|
vi.mock('../../../src/schemas/nutrition-target.schema.js', () => ({
|
2026-05-14 18:38:50 +09:00
|
|
|
NutritionTargetModel: MockTargetModel,
|
|
|
|
|
}));
|
|
|
|
|
|
2026-05-19 11:06:03 +09:00
|
|
|
const { NutritionTargetModel } = await import('../../../src/schemas/nutrition-target.schema.js');
|
2026-05-14 18:38:50 +09:00
|
|
|
|
|
|
|
|
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 } },
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
});
|
2026-05-19 10:13:40 +09:00
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
});
|
|
|
|
|
});
|
2026-05-14 18:38:50 +09:00
|
|
|
});
|