import { describe, it, expect } from 'vitest'; import { openInMemoryForTest } from '../../src/lib/server/db'; import { insertRecipe } from '../../src/lib/server/recipes/repository'; import { addRecipeToCart, removeRecipeFromCart, listShoppingList } from '../../src/lib/server/shopping/repository'; import type { Recipe } from '../../src/lib/types'; function recipe(overrides: Partial = {}): Recipe { return { id: null, title: 'Test', description: null, source_url: null, source_domain: null, image_path: null, servings_default: 4, servings_unit: null, prep_time_min: null, cook_time_min: null, total_time_min: null, cuisine: null, category: null, ingredients: [], steps: [], tags: [], ...overrides }; } describe('addRecipeToCart', () => { it('inserts recipe with default servings from recipe.servings_default', () => { const db = openInMemoryForTest(); const id = insertRecipe(db, recipe({ title: 'Pasta', servings_default: 4 })); addRecipeToCart(db, id, null); const snap = listShoppingList(db); expect(snap.recipes).toHaveLength(1); expect(snap.recipes[0].servings).toBe(4); }); it('respects explicit servings override', () => { const db = openInMemoryForTest(); const id = insertRecipe(db, recipe({ servings_default: 4 })); addRecipeToCart(db, id, null, 2); expect(listShoppingList(db).recipes[0].servings).toBe(2); }); it('is idempotent: second insert updates servings, not fails', () => { const db = openInMemoryForTest(); const id = insertRecipe(db, recipe({ servings_default: 4 })); addRecipeToCart(db, id, null, 2); addRecipeToCart(db, id, null, 6); const snap = listShoppingList(db); expect(snap.recipes).toHaveLength(1); expect(snap.recipes[0].servings).toBe(6); }); it('falls back to servings=4 when recipe has no default', () => { const db = openInMemoryForTest(); const id = insertRecipe(db, recipe({ servings_default: null })); addRecipeToCart(db, id, null); expect(listShoppingList(db).recipes[0].servings).toBe(4); }); }); describe('removeRecipeFromCart', () => { it('deletes only the given recipe', () => { const db = openInMemoryForTest(); const a = insertRecipe(db, recipe({ title: 'A' })); const b = insertRecipe(db, recipe({ title: 'B' })); addRecipeToCart(db, a, null); addRecipeToCart(db, b, null); removeRecipeFromCart(db, a); const snap = listShoppingList(db); expect(snap.recipes).toHaveLength(1); expect(snap.recipes[0].recipe_id).toBe(b); }); it('is idempotent when recipe is not in cart', () => { const db = openInMemoryForTest(); const id = insertRecipe(db, recipe()); expect(() => removeRecipeFromCart(db, id)).not.toThrow(); }); });