feat(recipes): filter ingredients with quantity <= 0 before API submission

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-10 09:05:19 +02:00
parent dbc78a1883
commit 44b3f06474
7 changed files with 65 additions and 15 deletions

View File

@@ -77,10 +77,10 @@ export const actions: Actions = {
effort,
heroImageUrl,
ingredients: (parsedIngredients as { name: string; quantity: string; unit: string }[])
.filter((ing) => ing.name?.trim())
.filter((ing) => ing.name?.trim() && Number(ing.quantity) > 0)
.map((ing, i) => ({
newIngredientName: ing.name.trim(),
quantity: Number(ing.quantity) || 0,
quantity: Number(ing.quantity),
unit: ing.unit || '',
sortOrder: i
})),

View File

@@ -204,6 +204,25 @@ describe('edit recipe page — update action', () => {
}));
});
it('filters out ingredients with quantity <= 0 before PUT', async () => {
mockPut.mockResolvedValue({ error: undefined });
const fd = makeFormData({
ingredientsJson: JSON.stringify([
{ name: 'Spaghetti', quantity: 200, unit: 'g' },
{ name: 'Salt', quantity: 0, unit: 'tsp' },
{ name: 'Pepper', quantity: -1, unit: 'tsp' }
])
});
await actions.update({
request: { formData: async () => fd },
fetch: vi.fn(),
params: { id: 'r1' }
} as any).catch(() => {});
const body = mockPut.mock.calls[0][1].body;
expect(body.ingredients).toHaveLength(1);
expect(body.ingredients[0].newIngredientName).toBe('Spaghetti');
});
it('returns fail(500) when API returns error', async () => {
mockPut.mockResolvedValue({ error: { status: 500 } });
const result = await actions.update({

View File

@@ -49,10 +49,10 @@ export const actions: Actions = {
effort,
heroImageUrl,
ingredients: (parsedIngredients as { name: string; quantity: string; unit: string }[])
.filter((ing) => ing.name?.trim())
.filter((ing) => ing.name?.trim() && Number(ing.quantity) > 0)
.map((ing, i) => ({
newIngredientName: ing.name.trim(),
quantity: Number(ing.quantity) || 0,
quantity: Number(ing.quantity),
unit: ing.unit || '',
sortOrder: i
})),

View File

@@ -163,6 +163,23 @@ describe('new recipe page — create action', () => {
}));
});
it('filters out ingredients with quantity <= 0 before POST', async () => {
mockPost.mockResolvedValue({ error: undefined });
const fd = makeFormData({
ingredientsJson: JSON.stringify([
{ name: 'Spaghetti', quantity: 200, unit: 'g' },
{ name: 'Salt', quantity: 0, unit: 'tsp' },
{ name: 'Pepper', quantity: -1, unit: 'tsp' }
])
});
await actions.create({ request: { formData: async () => fd }, fetch: vi.fn() } as any).catch(
() => {}
);
const body = mockPost.mock.calls[0][1].body;
expect(body.ingredients).toHaveLength(1);
expect(body.ingredients[0].newIngredientName).toBe('Spaghetti');
});
it('returns fail(500) when API returns error', async () => {
mockPost.mockResolvedValue({ error: { status: 500 } });
const result = await actions.create({

View File

@@ -5,9 +5,9 @@ import Page from './+page.svelte';
const mockData = {
recipes: [
{ id: 'r1', name: 'Spaghetti Bolognese', cookTimeMin: 30, effort: 'Easy' },
{ id: 'r2', name: 'Chicken Curry', cookTimeMin: 45, effort: 'Medium' },
{ id: 'r3', name: 'Gemüsesuppe', cookTimeMin: 20, effort: 'Easy' }
{ id: 'r1', name: 'Spaghetti Bolognese', cookTimeMin: 30, effort: 'easy' },
{ id: 'r2', name: 'Chicken Curry', cookTimeMin: 45, effort: 'medium' },
{ id: 'r3', name: 'Gemüsesuppe', cookTimeMin: 20, effort: 'easy' }
],
activePlan: null
};