import { describe, it, expect, vi } from 'vitest'; import { render, screen } from '@testing-library/svelte'; import userEvent from '@testing-library/user-event'; import RecipePicker from './RecipePicker.svelte'; const suggestions = [ { recipe: { id: 's1', name: 'Lachsfilet', effort: 'easy', cookTimeMin: 25 }, scoreDelta: 1.5, hasConflict: false }, { recipe: { id: 's2', name: 'Hähnchen-Curry', effort: 'easy', cookTimeMin: 35 }, scoreDelta: -1.5, hasConflict: true } ]; const allRecipes = [ { id: 'r1', name: 'Beef Bourguignon', effort: 'hard', cookTimeMin: 150 }, { id: 'r2', name: 'Spaghetti Carbonara', effort: 'easy', cookTimeMin: 20 }, { id: 'r3', name: 'Tomatensuppe', effort: 'easy', cookTimeMin: 30 } ]; const baseProps = { planId: 'plan-1', date: '2026-04-05', dateLabel: 'Samstag, 5. April', suggestions, allRecipes, onpick: vi.fn() }; describe('RecipePicker', () => { it('shows date label in header', () => { render(RecipePicker, { props: baseProps }); expect(screen.getByText('Samstag, 5. April')).toBeTruthy(); }); it('shows Empfohlen section', () => { render(RecipePicker, { props: baseProps }); expect(screen.getByText(/Empfohlen/i)).toBeTruthy(); }); it('shows all suggestion recipe names', () => { render(RecipePicker, { props: baseProps }); expect(screen.getByText('Lachsfilet')).toBeTruthy(); expect(screen.getByText('Hähnchen-Curry')).toBeTruthy(); }); it('shows green badge when hasConflict is false', () => { render(RecipePicker, { props: baseProps }); // Lachsfilet: hasConflict = false → green badge const badge = screen.getByTestId('badge-s1'); expect(badge.getAttribute('data-type')).toBe('good'); }); it('shows yellow badge when hasConflict is true', () => { render(RecipePicker, { props: baseProps }); // Hähnchen-Curry: hasConflict = true → yellow badge const badge = screen.getByTestId('badge-s2'); expect(badge.getAttribute('data-type')).toBe('warning'); }); it('shows Alle Rezepte section', () => { render(RecipePicker, { props: baseProps }); expect(screen.getByText(/Alle Rezepte/i)).toBeTruthy(); }); it('shows all recipe names in Alle Rezepte', () => { render(RecipePicker, { props: baseProps }); expect(screen.getByText('Beef Bourguignon')).toBeTruthy(); expect(screen.getByText('Spaghetti Carbonara')).toBeTruthy(); expect(screen.getByText('Tomatensuppe')).toBeTruthy(); }); it('filters recipes by search query', async () => { render(RecipePicker, { props: baseProps }); const input = screen.getByRole('searchbox'); await userEvent.type(input, 'Spaghetti'); expect(screen.queryByText('Beef Bourguignon')).toBeNull(); expect(screen.getByText('Spaghetti Carbonara')).toBeTruthy(); }); it('calls onpick with recipeId and name when Wählen clicked for suggestion', async () => { const onpick = vi.fn(); render(RecipePicker, { props: { ...baseProps, onpick } }); const buttons = screen.getAllByRole('button', { name: /Wählen/i }); await userEvent.click(buttons[0]); expect(onpick).toHaveBeenCalledWith('s1', 'Lachsfilet'); }); it('calls onpick when Wählen clicked for all-recipes item', async () => { const onpick = vi.fn(); render(RecipePicker, { props: { ...baseProps, onpick } }); const buttons = screen.getAllByRole('button', { name: /Wählen/i }); // First 2 are suggestions, rest are allRecipes await userEvent.click(buttons[2]); expect(onpick).toHaveBeenCalledWith('r1', 'Beef Bourguignon'); }); it('shows empty state when search has no results', async () => { render(RecipePicker, { props: baseProps }); const input = screen.getByRole('searchbox'); await userEvent.type(input, 'xyznotfound'); expect(screen.getByText(/Keine Treffer/i)).toBeTruthy(); }); it('shows loading skeleton instead of Empfohlen section when isLoading is true', () => { render(RecipePicker, { props: { ...baseProps, isLoading: true } }); expect(screen.getByTestId('suggestions-loading')).toBeTruthy(); expect(screen.queryByText(/Empfohlen/i)).toBeNull(); }); it('hides loading skeleton when isLoading is false and suggestions are present', () => { render(RecipePicker, { props: { ...baseProps, isLoading: false } }); expect(screen.queryByTestId('suggestions-loading')).toBeNull(); expect(screen.getByText(/Empfohlen/i)).toBeTruthy(); }); });