import { Test, TestingModule } from '@nestjs/testing' import { datatype } from 'faker' import { plainToClass } from 'class-transformer' import { FoodPlanRepository, MenuRepository, PatientRepository } from '../../../repositories' import { FoodPlan, MealGroup, Menu, Patient } from '../../../models' import { factory } from '../../../../test/factories' import { UserNotFoundError } from '../../../errors/user_not_found.error' import { FoodPlanAIService, STAG_MOCK_RESPONSE } from '../../../services' import { MockedModule } from '../../../../test/types' import { Nutrition } from './nutrition' describe('Nutrition', () => { let nutrition: Nutrition let patientRepository: MockedModule let menuRepository: MockedModule let foodPlanAIService: MockedModule let foodPlanRepository: MockedModule let patient: Patient let menuId = datatype.uuid() beforeAll(async () => { patientRepository = { get: jest.fn(), update: jest.fn(), } menuRepository = { findBy: jest.fn(), createWithRelationships: jest.fn(), } foodPlanAIService = { getFromPatientId: jest.fn(), } foodPlanRepository = { getWithRelationships: jest.fn(), } const app: TestingModule = await Test.createTestingModule({ controllers: [], providers: [ { provide: PatientRepository, useValue: patientRepository, }, { provide: MenuRepository, useValue: menuRepository, }, { provide: FoodPlanAIService, useValue: foodPlanAIService, }, { provide: FoodPlanRepository, useValue: foodPlanRepository, }, Nutrition, ], }).compile() nutrition = app.get(Nutrition) }) describe('#generateMenuToPatient', () => { const patientId = datatype.uuid() const subject = async (): Promise => { return await nutrition.generateMenuToPatient(patientId) } describe('when the patient exists', () => { beforeEach(async () => { patient = await factory.build('patient') patientRepository.get.mockResolvedValue(patient) }) const expectToSaveFromRandomMenu = () => { describe('and there is a random menu', () => { beforeEach(() => { menuRepository.findBy.mockResolvedValue(new Menu({ id: menuId })) }) it('updates the patient with the menu found', async () => { await subject() expect(patientRepository.update).toHaveBeenCalledWith( expect.objectContaining({ menu_id: menuId, }), ) }) }) describe('and there is not a random menu', () => { beforeEach(() => { menuRepository.findBy.mockResolvedValue([]) }) it('updates the patient without menu', async () => { await subject() expect(patientRepository.update).toHaveBeenCalledWith( expect.objectContaining({ menu_id: undefined, }), ) }) }) } describe('when food plan AI service returns valid', () => { beforeEach(async () => { foodPlanAIService.getFromPatientId.mockResolvedValue(STAG_MOCK_RESPONSE) }) describe('when food plan exists', () => { let foodPlan: FoodPlan let mealGroups: Array beforeEach(async () => { menuId = datatype.uuid() menuRepository.createWithRelationships.mockResolvedValue(menuId) const initialMealGroups = await factory.buildMany('meal_group', datatype.number({ min: 1, max: 10 })) const items = await factory.buildMany('meal_item', datatype.number({ min: 1, max: 10 })) mealGroups = await Promise.all( initialMealGroups.map(async group => plainToClass(MealGroup, { ...group, type: await factory.build('meal_type'), meals: Array.from(Array(datatype.number({ min: 1, max: 10 })), () => ({ id: datatype.uuid(), items, })), }), ), ) foodPlan = await factory.build('food_plan', { id: STAG_MOCK_RESPONSE.food_plan_id, meal_groups: mealGroups, }) foodPlanRepository.getWithRelationships.mockResolvedValue(foodPlan) }) it('creates a menu cloned from the food plan with the meal type time changes', async () => { await subject() const menu = plainToClass(FoodPlan, foodPlan).cloneToMenu(true) menu.changeMealGroupTimes(STAG_MOCK_RESPONSE.meal_time_adjusted, true) menu.meal_groups = menu.meal_groups.map(mealGroup => ({ ...mealGroup, meals: mealGroup.meals.map(meal => expect.objectContaining({ items: meal.items.map(mealItem => { delete mealItem.meal_id return expect.objectContaining(mealItem) }), }), ), })) as any expect(menuRepository.createWithRelationships).toHaveBeenCalledWith(menu) }) it('updates the patient with the menu found', async () => { await subject() expect(patientRepository.update).toHaveBeenCalledWith( expect.objectContaining({ menu_id: menuId, }), ) }) }) describe("when food plan doesn't exists", () => { beforeEach(async () => { foodPlanRepository.getWithRelationships.mockResolvedValue(null) }) expectToSaveFromRandomMenu() }) }) describe('when food plan AI service returns empty', () => { beforeEach(async () => { foodPlanAIService.getFromPatientId.mockResolvedValue(null) }) expectToSaveFromRandomMenu() }) }) describe('when the patient does not exist', () => { beforeEach(() => { patientRepository.get.mockResolvedValue(null) }) it('throws an UserNotFoundError', async () => { await expect(subject()).rejects.toThrowError(UserNotFoundError) }) }) }) })