- RecipeHero: render tag pills, min-h-[200px/240px], fix back link styling, remove font-[400] - IngredientList: sort by sortOrder ascending - StepList: aria-hidden on step circles - types.ts: add Tag, Ingredient, Step, RecipeDetail shared types - +page.svelte: add Edit link → /recipes/[id]/edit (desktop topbar) - Tests: tag pills, sortOrder sort, edit link, image variant, 403-as-404 documented Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
58 lines
2.3 KiB
TypeScript
58 lines
2.3 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { render, screen } from '@testing-library/svelte';
|
|
import IngredientList from './IngredientList.svelte';
|
|
|
|
const mockIngredients = [
|
|
{ ingredientId: 'i1', name: 'Spaghetti', quantity: 200, unit: 'g' },
|
|
{ ingredientId: 'i2', name: 'Hackfleisch', quantity: 400, unit: 'g' },
|
|
{ ingredientId: 'i3', name: 'Salz', quantity: undefined, unit: undefined }
|
|
];
|
|
|
|
describe('IngredientList', () => {
|
|
it('renders the section heading', () => {
|
|
render(IngredientList, { props: { ingredients: mockIngredients } });
|
|
expect(screen.getByText(/zutaten/i)).toBeInTheDocument();
|
|
});
|
|
|
|
it('renders a row for each ingredient', () => {
|
|
render(IngredientList, { props: { ingredients: mockIngredients } });
|
|
expect(screen.getByText('Spaghetti')).toBeInTheDocument();
|
|
expect(screen.getByText('Hackfleisch')).toBeInTheDocument();
|
|
expect(screen.getByText('Salz')).toBeInTheDocument();
|
|
});
|
|
|
|
it('renders quantity and unit when present', () => {
|
|
render(IngredientList, { props: { ingredients: mockIngredients } });
|
|
expect(screen.getByText('200 g')).toBeInTheDocument();
|
|
expect(screen.getByText('400 g')).toBeInTheDocument();
|
|
});
|
|
|
|
it('renders no quantity when not present', () => {
|
|
render(IngredientList, { props: { ingredients: mockIngredients } });
|
|
expect(screen.queryByText('undefined')).not.toBeInTheDocument();
|
|
});
|
|
|
|
it('has no remove buttons (read-only)', () => {
|
|
render(IngredientList, { props: { ingredients: mockIngredients } });
|
|
expect(screen.queryByRole('button')).not.toBeInTheDocument();
|
|
});
|
|
|
|
it('renders empty state when ingredients array is empty', () => {
|
|
render(IngredientList, { props: { ingredients: [] } });
|
|
expect(screen.getByText(/zutaten/i)).toBeInTheDocument();
|
|
});
|
|
|
|
it('renders ingredients sorted by sortOrder', () => {
|
|
const unsorted = [
|
|
{ ingredientId: 'i3', name: 'Oregano', quantity: 1, unit: 'TL', sortOrder: 3 },
|
|
{ ingredientId: 'i1', name: 'Spaghetti', quantity: 200, unit: 'g', sortOrder: 1 },
|
|
{ ingredientId: 'i2', name: 'Hackfleisch', quantity: 400, unit: 'g', sortOrder: 2 }
|
|
];
|
|
render(IngredientList, { props: { ingredients: unsorted } });
|
|
const spans = document.querySelectorAll('li span:last-child');
|
|
expect(spans[0].textContent).toBe('Spaghetti');
|
|
expect(spans[1].textContent).toBe('Hackfleisch');
|
|
expect(spans[2].textContent).toBe('Oregano');
|
|
});
|
|
});
|