import { describe, it, expect, beforeEach } from 'vitest'; import type Database from 'better-sqlite3'; import { openInMemoryForTest } from '../../src/lib/server/db'; import { createProfile } from '../../src/lib/server/profiles/repository'; import { insertRecipe } from '../../src/lib/server/recipes/repository'; import { addToWishlist, removeFromWishlist, removeFromWishlistForAll, listWishlist, listWishlistProfileIds, isOnMyWishlist, countWishlistRecipes } from '../../src/lib/server/wishlist/repository'; import type { Recipe } from '../../src/lib/types'; const recipe = (title: string, id?: null): Recipe => ({ id: id ?? null, title, 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: [] }); let db: Database.Database; beforeEach(() => { db = openInMemoryForTest(); }); describe('per-user wishlist', () => { it('adds and lists for a single profile', () => { const r1 = insertRecipe(db, recipe('Carbonara')); const p = createProfile(db, 'Hendrik'); addToWishlist(db, r1, p.id); expect(isOnMyWishlist(db, r1, p.id)).toBe(true); const list = listWishlist(db, p.id); expect(list.length).toBe(1); expect(list[0].title).toBe('Carbonara'); expect(list[0].wanted_by_count).toBe(1); expect(list[0].wanted_by_names).toBe('Hendrik'); expect(list[0].on_my_wishlist).toBe(1); }); it('aggregates multiple users per recipe', () => { const r1 = insertRecipe(db, recipe('Pizza')); const a = createProfile(db, 'Alice'); const b = createProfile(db, 'Bob'); const c = createProfile(db, 'Cara'); addToWishlist(db, r1, a.id); addToWishlist(db, r1, b.id); addToWishlist(db, r1, c.id); const listFromA = listWishlist(db, a.id); expect(listFromA.length).toBe(1); expect(listFromA[0].wanted_by_count).toBe(3); expect(listFromA[0].on_my_wishlist).toBe(1); const ids = listWishlistProfileIds(db, r1); expect(ids.sort()).toEqual([a.id, b.id, c.id].sort()); }); it('is idempotent on double-add for same profile', () => { const r1 = insertRecipe(db, recipe('Pizza')); const p = createProfile(db, 'A'); addToWishlist(db, r1, p.id); addToWishlist(db, r1, p.id); const list = listWishlist(db, p.id); expect(list[0].wanted_by_count).toBe(1); }); it('removes only my entry, keeps others', () => { const r1 = insertRecipe(db, recipe('Salad')); const a = createProfile(db, 'A'); const b = createProfile(db, 'B'); addToWishlist(db, r1, a.id); addToWishlist(db, r1, b.id); removeFromWishlist(db, r1, a.id); expect(isOnMyWishlist(db, r1, a.id)).toBe(false); expect(isOnMyWishlist(db, r1, b.id)).toBe(true); expect(listWishlist(db, b.id)[0].wanted_by_count).toBe(1); }); it('on_my_wishlist is 0 for profiles that did not wish', () => { const r1 = insertRecipe(db, recipe('Curry')); const a = createProfile(db, 'A'); const b = createProfile(db, 'B'); addToWishlist(db, r1, a.id); const listFromB = listWishlist(db, b.id); expect(listFromB[0].on_my_wishlist).toBe(0); expect(listFromB[0].wanted_by_count).toBe(1); }); it('cascades when recipe is deleted', () => { const r1 = insertRecipe(db, recipe('X')); const a = createProfile(db, 'A'); addToWishlist(db, r1, a.id); db.prepare('DELETE FROM recipe WHERE id = ?').run(r1); expect(listWishlist(db, a.id).length).toBe(0); }); it('cascades when profile is deleted', () => { const r1 = insertRecipe(db, recipe('X')); const a = createProfile(db, 'A'); addToWishlist(db, r1, a.id); db.prepare('DELETE FROM profile WHERE id = ?').run(a.id); expect(listWishlist(db, null).length).toBe(0); }); it('countWishlistRecipes counts distinct recipes (not rows)', () => { const r1 = insertRecipe(db, recipe('R1')); const r2 = insertRecipe(db, recipe('R2')); const a = createProfile(db, 'A'); const b = createProfile(db, 'B'); addToWishlist(db, r1, a.id); addToWishlist(db, r1, b.id); // same recipe, different user addToWishlist(db, r2, a.id); expect(countWishlistRecipes(db)).toBe(2); }); it('removeFromWishlistForAll drops every profile', () => { const r1 = insertRecipe(db, recipe('R1')); const a = createProfile(db, 'A'); const b = createProfile(db, 'B'); addToWishlist(db, r1, a.id); addToWishlist(db, r1, b.id); removeFromWishlistForAll(db, r1); expect(listWishlistProfileIds(db, r1)).toEqual([]); }); });