diff --git a/frontend/src/lib/recipes/RecipeHero.svelte b/frontend/src/lib/recipes/RecipeHero.svelte new file mode 100644 index 0000000..9674f6c --- /dev/null +++ b/frontend/src/lib/recipes/RecipeHero.svelte @@ -0,0 +1,67 @@ + + +
+ {#if hasImage} + {recipe.name} +
+ {/if} + +
+ ← Zurück + +

+ {recipe.name} +

+ +
+ {#if recipe.cookTimeMin != null} + {recipe.cookTimeMin} Min + {/if} + {#if recipe.effort} + {recipe.effort} + {/if} + {#if recipe.serves != null} + {recipe.serves} Port. + {/if} +
+ + Jetzt kochen +
+
diff --git a/frontend/src/lib/recipes/RecipeHero.test.ts b/frontend/src/lib/recipes/RecipeHero.test.ts new file mode 100644 index 0000000..54c4d40 --- /dev/null +++ b/frontend/src/lib/recipes/RecipeHero.test.ts @@ -0,0 +1,66 @@ +import { describe, it, expect } from 'vitest'; +import { render, screen } from '@testing-library/svelte'; +import RecipeHero from './RecipeHero.svelte'; + +const baseRecipe = { + id: 'r1', + name: 'Spaghetti Bolognese', + serves: 4, + cookTimeMin: 30, + effort: 'Easy', + heroImageUrl: undefined as string | undefined, + tags: [] as { id: string; name: string; tagType?: string }[] +}; + +describe('RecipeHero', () => { + it('renders the recipe name', () => { + render(RecipeHero, { props: { recipe: baseRecipe } }); + expect(screen.getByText('Spaghetti Bolognese')).toBeInTheDocument(); + }); + + it('renders green-tint hero when no image', () => { + render(RecipeHero, { props: { recipe: baseRecipe } }); + const hero = document.querySelector('[data-testid="recipe-hero"]'); + expect(hero?.className).toContain('bg-[var(--green-tint)]'); + }); + + it('renders image when heroImageUrl is provided', () => { + render(RecipeHero, { + props: { recipe: { ...baseRecipe, heroImageUrl: '/uploads/pasta.jpg' } } + }); + const img = screen.getByRole('img', { name: /spaghetti bolognese/i }); + expect(img).toHaveAttribute('src', '/uploads/pasta.jpg'); + }); + + it('renders cook time pill', () => { + render(RecipeHero, { props: { recipe: baseRecipe } }); + expect(screen.getByText(/30 Min/)).toBeInTheDocument(); + }); + + it('renders effort pill', () => { + render(RecipeHero, { props: { recipe: baseRecipe } }); + expect(screen.getByText(/Easy/)).toBeInTheDocument(); + }); + + it('renders serves pill', () => { + render(RecipeHero, { props: { recipe: baseRecipe } }); + expect(screen.getByText(/4/)).toBeInTheDocument(); + }); + + it('renders back link to /recipes', () => { + render(RecipeHero, { props: { recipe: baseRecipe } }); + const backLink = screen.getByRole('link', { name: /zurück/i }); + expect(backLink).toHaveAttribute('href', '/recipes'); + }); + + it('renders cook now link to /cook/[id]', () => { + render(RecipeHero, { props: { recipe: baseRecipe } }); + const cookLink = screen.getByRole('link', { name: /jetzt kochen/i }); + expect(cookLink).toHaveAttribute('href', '/cook/r1'); + }); + + it('does not render img when no heroImageUrl', () => { + render(RecipeHero, { props: { recipe: baseRecipe } }); + expect(screen.queryByRole('img')).not.toBeInTheDocument(); + }); +});