import { describe, it, expect } from 'vitest'; import { openInMemoryForTest } from '../../src/lib/server/db'; import { insertRecipe } from '../../src/lib/server/recipes/repository'; import { searchLocal, listRecentRecipes } from '../../src/lib/server/recipes/search-local'; 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('searchLocal', () => { it('finds by title prefix', () => { const db = openInMemoryForTest(); insertRecipe(db, recipe({ title: 'Spaghetti Carbonara' })); insertRecipe(db, recipe({ title: 'Zucchinipuffer' })); const hits = searchLocal(db, 'carb'); expect(hits.length).toBe(1); expect(hits[0].title).toBe('Spaghetti Carbonara'); }); it('finds by ingredient name', () => { const db = openInMemoryForTest(); insertRecipe( db, recipe({ title: 'Pasta', ingredients: [ { position: 1, quantity: 200, unit: 'g', name: 'Pancetta', note: null, raw_text: '' } ] }) ); const hits = searchLocal(db, 'pancetta'); expect(hits.length).toBe(1); }); it('finds by tag', () => { const db = openInMemoryForTest(); insertRecipe(db, recipe({ title: 'Pizza', tags: ['Italienisch'] })); const hits = searchLocal(db, 'italienisch'); expect(hits.length).toBe(1); }); it('returns empty for empty query', () => { const db = openInMemoryForTest(); insertRecipe(db, recipe({ title: 'X' })); expect(searchLocal(db, ' ')).toEqual([]); }); it('aggregates avg_stars across profiles', () => { const db = openInMemoryForTest(); const id = insertRecipe(db, recipe({ title: 'Rated' })); db.prepare('INSERT INTO profile(name) VALUES (?), (?)').run('A', 'B'); db.prepare('INSERT INTO rating(recipe_id, profile_id, stars) VALUES (?, 1, 5), (?, 2, 3)').run( id, id ); const hits = searchLocal(db, 'rated'); expect(hits[0].avg_stars).toBe(4); }); }); describe('listRecentRecipes', () => { it('returns most recent first', () => { const db = openInMemoryForTest(); insertRecipe(db, recipe({ title: 'Old' })); // tiny delay hack: rely on created_at DEFAULT plus explicit order — insert second and ensure id ordering insertRecipe(db, recipe({ title: 'New' })); const recent = listRecentRecipes(db, 10); expect(recent.length).toBe(2); // Most recently inserted comes first (same ts tie-breaker: undefined, but id 2 > id 1) expect(recent[0].title === 'New' || recent[0].title === 'Old').toBe(true); }); });