diff --git a/frontend/src/lib/recipes/RecipeCard.svelte b/frontend/src/lib/recipes/RecipeCard.svelte new file mode 100644 index 0000000..97f9d81 --- /dev/null +++ b/frontend/src/lib/recipes/RecipeCard.svelte @@ -0,0 +1,66 @@ + + + + + {#if recipe.heroImageUrl} + + {:else} + + + + + + + + + + {/if} + + + + {recipe.name} + {#if metadata} + {metadata} + {/if} + + diff --git a/frontend/src/lib/recipes/RecipeCard.test.ts b/frontend/src/lib/recipes/RecipeCard.test.ts new file mode 100644 index 0000000..f9792a4 --- /dev/null +++ b/frontend/src/lib/recipes/RecipeCard.test.ts @@ -0,0 +1,62 @@ +import { describe, it, expect, vi } from 'vitest'; +import { render, screen } from '@testing-library/svelte'; +import { userEvent } from '@testing-library/user-event'; +import RecipeCard from './RecipeCard.svelte'; + +const mockRecipe = { + id: 'recipe-1', + name: 'Spaghetti Bolognese', + cookTimeMin: 30, + effort: 'Easy', + heroImageUrl: undefined +}; + +describe('RecipeCard', () => { + it('renders the recipe name', () => { + render(RecipeCard, { props: { recipe: mockRecipe } }); + expect(screen.getByText('Spaghetti Bolognese')).toBeInTheDocument(); + }); + + it('renders cook time when present', () => { + render(RecipeCard, { props: { recipe: mockRecipe } }); + expect(screen.getByText(/30/)).toBeInTheDocument(); + }); + + it('renders effort when present', () => { + render(RecipeCard, { props: { recipe: mockRecipe } }); + expect(screen.getByText(/easy/i)).toBeInTheDocument(); + }); + + it('shows placeholder when no heroImageUrl', () => { + render(RecipeCard, { props: { recipe: { ...mockRecipe, heroImageUrl: undefined } } }); + expect(screen.queryByRole('img')).not.toBeInTheDocument(); + expect(document.querySelector('[data-testid="image-placeholder"]')).toBeInTheDocument(); + }); + + it('shows image when heroImageUrl is provided', () => { + render(RecipeCard, { + props: { recipe: { ...mockRecipe, heroImageUrl: '/uploads/test.jpg' } } + }); + const img = screen.getByRole('img'); + expect(img).toHaveAttribute('src', '/uploads/test.jpg'); + expect(img).toHaveAttribute('alt', 'Spaghetti Bolognese'); + }); + + it('wraps in a link to the recipe detail page', () => { + render(RecipeCard, { props: { recipe: mockRecipe } }); + const link = screen.getByRole('link'); + expect(link).toHaveAttribute('href', '/recipes/recipe-1'); + }); + + it('applies compact image height when compact prop is true', () => { + render(RecipeCard, { props: { recipe: mockRecipe, compact: true } }); + const imageArea = document.querySelector('[data-testid="image-area"]'); + expect(imageArea?.className).toContain('h-[64px]'); + }); + + it('applies full image height when compact prop is false', () => { + render(RecipeCard, { props: { recipe: mockRecipe, compact: false } }); + const imageArea = document.querySelector('[data-testid="image-area"]'); + expect(imageArea?.className).toContain('h-[100px]'); + }); +});
{recipe.name}
{metadata}