import { describe, it, expect, vi } from 'vitest'; import { render, screen } from '@testing-library/svelte'; import userEvent from '@testing-library/user-event'; import DayPicker from './DayPicker.svelte'; const weekStart = '2026-03-30'; // Monday const today = '2026-04-01'; // Wednesday // Mo: filled, Di: filled (today), Mi: filled, Do: empty, Fr: filled, Sa: empty, So: filled const slots = [ { id: 's1', slotDate: '2026-03-30', recipe: { id: 'r1', name: 'Pasta', effort: 'easy' } }, { id: 's2', slotDate: '2026-04-01', recipe: { id: 'r2', name: 'Curry', effort: 'easy' } }, { id: 's3', slotDate: '2026-04-02', recipe: { id: 'r3', name: 'Risotto', effort: 'medium' } }, { id: 's5', slotDate: '2026-04-04', recipe: { id: 'r5', name: 'Suppe', effort: 'easy' } }, { id: 's7', slotDate: '2026-04-06', recipe: { id: 'r7', name: 'Stir Fry', effort: 'easy' } } ]; const baseProps = { recipeName: 'Mushroom Risotto', recipeId: 'recipe-42', planId: 'plan-1', weekStart, today, slots, onconfirm: vi.fn(), onweekchange: vi.fn() }; describe('DayPicker', () => { it('shows recipe name in header', () => { render(DayPicker, { props: baseProps }); expect(screen.getByText('Mushroom Risotto')).toBeTruthy(); }); it('shows 7 day chips', () => { render(DayPicker, { props: baseProps }); const chips = screen.getAllByTestId(/^chip-/); expect(chips).toHaveLength(7); }); it('marks empty slot chips with data-state="empty"', () => { render(DayPicker, { props: baseProps }); // Do (2026-04-03) and Sa (2026-04-05) are empty const doChip = screen.getByTestId('chip-2026-04-03'); expect(doChip.getAttribute('data-state')).toBe('empty'); }); it('marks filled slot chips with data-state="filled"', () => { render(DayPicker, { props: baseProps }); const moChip = screen.getByTestId('chip-2026-03-30'); expect(moChip.getAttribute('data-state')).toBe('filled'); }); it('marks today chip with data-state="today"', () => { render(DayPicker, { props: baseProps }); const todayChip = screen.getByTestId('chip-2026-04-01'); expect(todayChip.getAttribute('data-state')).toBe('today'); }); it('selecting an empty chip changes its state to sel-empty', async () => { render(DayPicker, { props: baseProps }); const doChip = screen.getByTestId('chip-2026-04-03'); await userEvent.click(doChip); expect(doChip.getAttribute('data-state')).toBe('sel-empty'); }); it('selecting a filled chip changes its state to sel-filled', async () => { render(DayPicker, { props: baseProps }); const moChip = screen.getByTestId('chip-2026-03-30'); await userEvent.click(moChip); expect(moChip.getAttribute('data-state')).toBe('sel-filled'); }); it('shows replace warning when filled chip is selected', async () => { render(DayPicker, { props: baseProps }); const moChip = screen.getByTestId('chip-2026-03-30'); await userEvent.click(moChip); expect(screen.getByTestId('replace-warning')).toBeTruthy(); expect(screen.getByText(/Pasta/)).toBeTruthy(); }); it('does not show replace warning when empty chip is selected', async () => { render(DayPicker, { props: baseProps }); const doChip = screen.getByTestId('chip-2026-04-03'); await userEvent.click(doChip); expect(screen.queryByTestId('replace-warning')).toBeNull(); }); it('confirm button is disabled when no chip is selected', () => { render(DayPicker, { props: baseProps }); const btn = screen.getByTestId('confirm-btn'); expect(btn.hasAttribute('disabled')).toBe(true); }); it('calls onconfirm with date and null slotId when empty chip confirmed', async () => { const onconfirm = vi.fn(); render(DayPicker, { props: { ...baseProps, onconfirm } }); const doChip = screen.getByTestId('chip-2026-04-03'); await userEvent.click(doChip); const btn = screen.getByTestId('confirm-btn'); await userEvent.click(btn); expect(onconfirm).toHaveBeenCalledWith({ date: '2026-04-03', slotId: null }); }); it('calls onconfirm with date and slotId when filled chip confirmed', async () => { const onconfirm = vi.fn(); render(DayPicker, { props: { ...baseProps, onconfirm } }); const moChip = screen.getByTestId('chip-2026-03-30'); await userEvent.click(moChip); const btn = screen.getByTestId('confirm-btn'); await userEvent.click(btn); expect(onconfirm).toHaveBeenCalledWith({ date: '2026-03-30', slotId: 's1' }); }); it('shows prev/next week navigation buttons', () => { render(DayPicker, { props: baseProps }); expect(screen.getByRole('button', { name: /Vorherige Woche/ })).toBeTruthy(); expect(screen.getByRole('button', { name: /Nächste Woche/ })).toBeTruthy(); }); it('calls onweekchange with prev week when prev button clicked', async () => { const onweekchange = vi.fn(); render(DayPicker, { props: { ...baseProps, onweekchange } }); await userEvent.click(screen.getByRole('button', { name: /Vorherige Woche/ })); expect(onweekchange).toHaveBeenCalledWith('2026-03-23'); }); it('calls onweekchange with next week when next button clicked', async () => { const onweekchange = vi.fn(); render(DayPicker, { props: { ...baseProps, onweekchange } }); await userEvent.click(screen.getByRole('button', { name: /Nächste Woche/ })); expect(onweekchange).toHaveBeenCalledWith('2026-04-06'); }); });