feat(planner): add remove meal with undo; fix RecipePicker badge for neutral delta
- MealActionSheet: new onremove prop + Entfernen button (guarded by #if) - +page.svelte: handleRemoveMeal submits delete form, shows undo bar; undo re-adds via addSlot form; refactored handleUndo to undoCallback pattern; desktop day-detail panel also gets Entfernen button - RecipePicker: only show green +delta badge when scoreDelta > 0; neutral (scoreDelta = 0) shows no badge instead of ⚠ Variationskonflikt - Tests: page.test.ts remove-meal describe, RecipePicker neutral badge test Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { describe, it, expect, vi, afterEach } from 'vitest';
|
||||
import { render, screen, waitFor } from '@testing-library/svelte';
|
||||
import { render, screen, waitFor, within } from '@testing-library/svelte';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import Page from './+page.svelte';
|
||||
|
||||
@@ -13,13 +13,23 @@ const PLAN_ID = 'plan-00000000-0000-0000-0000-000000000001';
|
||||
const DATE = '2025-01-06'; // Monday, January 6 2025
|
||||
|
||||
const mockData = {
|
||||
weekPlan: { id: PLAN_ID, weekStart: DATE, status: 'draft', slots: [] },
|
||||
weekPlan: { id: PLAN_ID, weekStart: DATE, status: 'draft', slots: [] as any[] },
|
||||
varietyScore: null,
|
||||
weekStart: DATE,
|
||||
recipes: [{ id: 'r1', name: 'Beef Bourguignon', effort: 'hard', cookTimeMin: 150 }],
|
||||
benutzer: { rolle: 'planer' }
|
||||
};
|
||||
|
||||
const mockDataWithSlot = {
|
||||
...mockData,
|
||||
weekPlan: {
|
||||
id: PLAN_ID,
|
||||
weekStart: DATE,
|
||||
status: 'draft',
|
||||
slots: [{ id: 'slot-1', slotDate: DATE, recipe: { id: 'r1', name: 'Beef Bourguignon', effort: 'hard', cookTimeMin: 150 } }]
|
||||
}
|
||||
};
|
||||
|
||||
const mockSuggestions = [
|
||||
{
|
||||
recipe: { id: 's1', name: 'Lachsfilet', effort: 'easy', cookTimeMin: 20 },
|
||||
@@ -82,3 +92,35 @@ describe('+page.svelte — $effect suggestion fetch', () => {
|
||||
expect(fetchOptions?.signal).toBeInstanceOf(AbortSignal);
|
||||
});
|
||||
});
|
||||
|
||||
describe('+page.svelte — remove meal', () => {
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('clicking Entfernen in MealActionSheet shows undo bar with recipe name', async () => {
|
||||
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ json: () => Promise.resolve({ suggestions: [] }) }));
|
||||
|
||||
render(Page, { props: { data: mockDataWithSlot } });
|
||||
|
||||
await userEvent.click(screen.getByTestId('day-meal-card'));
|
||||
await userEvent.click(await screen.findByRole('button', { name: /Entfernen/i }));
|
||||
|
||||
const undoBar = screen.getByTestId('undo-bar');
|
||||
expect(undoBar).toBeTruthy();
|
||||
expect(within(undoBar).getByText(/Beef Bourguignon/)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('clicking Rückgängig after remove hides the undo bar', async () => {
|
||||
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ json: () => Promise.resolve({ suggestions: [] }) }));
|
||||
|
||||
render(Page, { props: { data: mockDataWithSlot } });
|
||||
|
||||
await userEvent.click(screen.getByTestId('day-meal-card'));
|
||||
await userEvent.click(await screen.findByRole('button', { name: /Entfernen/i }));
|
||||
|
||||
await userEvent.click(screen.getByRole('button', { name: /Rückgängig/i }));
|
||||
|
||||
expect(screen.queryByTestId('undo-bar')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user