process.env.CALORIE_PROVIDER = 'none'; import { addMeal, getDay } from "../meals"; import { fillMealGroup, getMealGroups, renameMealGroup } from "../mealGroups"; import { searchCalories } from "../calories"; import { resetMemoryStorage } from "../storage/memory"; import { MealType } from "../../../types/gen/types.gen"; const LOGIN = 'tester'; beforeEach(() => resetMemoryStorage()); const cina = { mealType: MealType.OBED, name: 'Čína', source: 'Chefie' }; describe('skupiny jídel podle názvu a zdroje', () => { it('seskupí jídla podle názvu i zdroje a spočítá chybějící údaje', async () => { await addMeal(LOGIN, { ...cina, date: '2025-03-01', price: 13900 }); await addMeal(LOGIN, { ...cina, date: '2025-03-02', name: 'cina', price: 14900 }); await addMeal(LOGIN, { ...cina, date: '2025-03-03', price: 14900, weight: 400, caloriesPer100g: 150 }); await addMeal(LOGIN, { ...cina, date: '2025-03-04', source: 'doma' }); const groups = await getMealGroups(LOGIN); expect(groups).toHaveLength(2); expect(groups[0]).toMatchObject({ name: 'Čína', source: 'Chefie', count: 3, lastDate: '2025-03-03', missingCaloriesCount: 2, missingWeightCount: 2, missingNutrientsCount: 3, values: { weight: 400, caloriesPer100g: 150 }, days: [ { date: '2025-03-03', incomplete: true }, { date: '2025-03-02', incomplete: true }, { date: '2025-03-01', incomplete: true }, ], }); expect(groups[1]).toMatchObject({ source: 'doma', count: 1 }); }); it('u dnů skupiny označí ty, kde jídlu něco chybí', async () => { await addMeal(LOGIN, { ...cina, date: '2025-03-01', weight: 400, caloriesPer100g: 150, nutrientsPer100g: { protein: 8 }, }); await addMeal(LOGIN, { ...cina, date: '2025-03-02', price: 13900 }); const [group] = await getMealGroups(LOGIN); expect(group.days).toEqual([ { date: '2025-03-02', incomplete: true }, { date: '2025-03-01', incomplete: false }, ]); }); it('energii a živiny předvyplní i z jídla stejného názvu odjinud, sazbu ne', async () => { await addMeal(LOGIN, { ...cina, date: '2025-03-01', source: 'doma', pricePer100g: 2000, caloriesPer100g: 140, nutrientsPer100g: { protein: 8 }, }); await addMeal(LOGIN, { ...cina, date: '2025-03-02', price: 13900 }); const group = (await getMealGroups(LOGIN)).find(item => item.source === 'Chefie'); expect(group?.values).toEqual({ caloriesPer100g: 140, nutrientsPer100g: { protein: 8 } }); }); }); describe('hromadné doplnění údajů do skupiny', () => { it('doplní jen chybějící hodnoty a kalorie dopočte z gramáže', async () => { await addMeal(LOGIN, { ...cina, date: '2025-03-01', price: 13900 }); await addMeal(LOGIN, { ...cina, date: '2025-03-02', price: 14900, weight: 300 }); await addMeal(LOGIN, { ...cina, date: '2025-03-03', price: 14900, calories: 700 }); await addMeal(LOGIN, { ...cina, date: '2025-03-04', source: 'doma' }); const result = await fillMealGroup(LOGIN, 'cina', 'chefie', { weight: 400, caloriesPer100g: 150, nutrientsPer100g: { protein: 8 }, }); expect(result).toEqual({ count: 3, dates: ['2025-03-01', '2025-03-02', '2025-03-03'] }); expect((await getDay(LOGIN, '2025-03-01')).entries[0]).toMatchObject({ weight: 400, calories: 600, price: 13900 }); expect((await getDay(LOGIN, '2025-03-02')).entries[0]).toMatchObject({ weight: 300, calories: 450 }); // Ručně zadané kalorie zůstanou, energie na 100 g by je přepočítala const third = (await getDay(LOGIN, '2025-03-03')).entries[0]; expect(third).toMatchObject({ weight: 400, calories: 700, nutrientsPer100g: { protein: 8 } }); expect(third.caloriesPer100g).toBeUndefined(); expect((await getDay(LOGIN, '2025-03-04')).entries[0].calories).toBeUndefined(); }); it('gramáž dopočte z vlastní ceny jídla, když přibude sazba', async () => { await addMeal(LOGIN, { ...cina, date: '2025-03-01', price: 13200 }); await fillMealGroup(LOGIN, 'Čína', 'Chefie', { pricePer100g: 4400, weight: 400, caloriesPer100g: 150 }); expect((await getDay(LOGIN, '2025-03-01')).entries[0]).toMatchObject({ weight: 300, calories: 450 }); }); it('vyplněné živiny nepřepíše, chybějící doplní', async () => { await addMeal(LOGIN, { ...cina, date: '2025-03-01', nutrientsPer100g: { protein: 5 } }); await fillMealGroup(LOGIN, 'Čína', 'Chefie', { nutrientsPer100g: { protein: 8, fat: 4 } }); expect((await getDay(LOGIN, '2025-03-01')).entries[0].nutrientsPer100g).toEqual({ protein: 5, fat: 4 }); }); it('jídla, kterým nic nechybí, nepočítá', async () => { await addMeal(LOGIN, { ...cina, date: '2025-03-01', weight: 300, caloriesPer100g: 150 }); const result = await fillMealGroup(LOGIN, 'Čína', 'Chefie', { weight: 400, caloriesPer100g: 200 }); expect(result).toEqual({ count: 0, dates: [] }); expect((await getDay(LOGIN, '2025-03-01')).entries[0].calories).toBe(450); }); it('bez zdroje doplní jen jídla bez zdroje', async () => { await addMeal(LOGIN, { ...cina, date: '2025-03-01', source: undefined }); await addMeal(LOGIN, { ...cina, date: '2025-03-02' }); const result = await fillMealGroup(LOGIN, 'Čína', undefined, { calories: 600 }); expect(result.dates).toEqual(['2025-03-01']); expect((await getDay(LOGIN, '2025-03-02')).entries[0].calories).toBeUndefined(); }); }); describe('přejmenování skupiny jídel', () => { it('přejmenuje a přesune do jiného zdroje všechna jídla skupiny', async () => { await addMeal(LOGIN, { ...cina, date: '2025-03-01', price: 13900 }); await addMeal(LOGIN, { ...cina, date: '2025-03-02', name: 'cina' }); await addMeal(LOGIN, { ...cina, date: '2025-03-02', source: 'doma' }); const result = await renameMealGroup(LOGIN, 'Čína', 'Chefie', 'Kuře kung-pao', 'Everest'); expect(result).toEqual({ count: 2, dates: ['2025-03-01', '2025-03-02'] }); expect((await getDay(LOGIN, '2025-03-01')).entries[0]) .toMatchObject({ name: 'Kuře kung-pao', source: 'Everest', price: 13900 }); const second = (await getDay(LOGIN, '2025-03-02')).entries; expect(second.map(entry => `${entry.name}|${entry.source}`).sort()) .toEqual(['Kuře kung-pao|Everest', 'Čína|doma']); }); it('prázdný zdroj zdroj odebere a jídla se sloučí se skupinou bez zdroje', async () => { await addMeal(LOGIN, { ...cina, date: '2025-03-01' }); await addMeal(LOGIN, { ...cina, date: '2025-03-02', source: undefined }); await renameMealGroup(LOGIN, 'Čína', 'Chefie', 'Čína', undefined); const groups = await getMealGroups(LOGIN); expect(groups).toHaveLength(1); expect(groups[0].count).toBe(2); expect((await getDay(LOGIN, '2025-03-01')).entries[0]).not.toHaveProperty('source'); }); it('jídla se shodným zápisem nepočítá', async () => { await addMeal(LOGIN, { ...cina, date: '2025-03-01' }); await addMeal(LOGIN, { ...cina, date: '2025-03-02', name: 'čína' }); const result = await renameMealGroup(LOGIN, 'Čína', 'Chefie', 'Čína', 'Chefie'); expect(result).toEqual({ count: 1, dates: ['2025-03-02'] }); }); it('energii na 100 g si knihovna zapamatuje i pod novým názvem', async () => { await addMeal(LOGIN, { ...cina, date: '2025-03-01', weight: 400, caloriesPer100g: 150 }); await renameMealGroup(LOGIN, 'Čína', 'Chefie', 'Kuře kung-pao', 'Chefie'); const { suggestions } = await searchCalories(LOGIN, 'Kuře kung-pao'); expect(suggestions[0]).toMatchObject({ name: 'Kuře kung-pao', caloriesPer100g: 150 }); }); it('odmítne prázdný nový název', async () => { await expect(renameMealGroup(LOGIN, 'Čína', 'Chefie', ' ', 'Chefie')).rejects.toThrow(/nový název/); }); });