7-chip week strip with 5 slot states, inline replace warning, confirm button, and prev/next week navigation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
135 lines
5.1 KiB
TypeScript
135 lines
5.1 KiB
TypeScript
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');
|
|
});
|
|
});
|