import React from 'react'; import { describe, it, expect, vi } from 'vitest'; import { render, screen, fireEvent } from '@testing-library/react'; import { KanbanBoard } from '@/components/calendar/KanbanBoard'; import type { CalendarEntry } from '@/api/calendar'; function makeTask(id: string, title: string, status: CalendarEntry['status']): CalendarEntry { return { id, calendar_id: 'cal-1', entry_type: 'task', subtype: 'normal', title, all_day: false, priority: 'medium', status, created_by: 'u-1', due_date: '2026-07-01T00:00:00.000Z', }; } const board = { open: [makeTask('t-1', 'Recherche', 'open')], in_progress: [makeTask('t-2', 'Implementierung', 'in_progress')], done: [makeTask('t-3', 'Tests', 'done')], cancelled: [], }; describe('KanbanBoard', () => { it('renders three columns (open / in_progress / done)', () => { render(); expect(screen.getByTestId('kanban-column-open')).toBeInTheDocument(); expect(screen.getByTestId('kanban-column-in_progress')).toBeInTheDocument(); expect(screen.getByTestId('kanban-column-done')).toBeInTheDocument(); }); it('renders task cards inside the correct columns', () => { render(); expect(screen.getByTestId('kanban-card-t-1').textContent).toContain('Recherche'); expect(screen.getByTestId('kanban-card-t-2').textContent).toContain('Implementierung'); expect(screen.getByTestId('kanban-card-t-3').textContent).toContain('Tests'); }); it('shows column counts', () => { render(); expect(screen.getByTestId('kanban-count-open').textContent).toBe('1'); expect(screen.getByTestId('kanban-count-in_progress').textContent).toBe('1'); expect(screen.getByTestId('kanban-count-done').textContent).toBe('1'); }); it('shows empty state when there are no tasks', () => { render( ); expect(screen.getByTestId('kanban-empty')).toBeInTheDocument(); }); it('drag-and-drop into another column fires onMove with target status', () => { const onMove = vi.fn(); render(); const card = screen.getByTestId('kanban-card-t-1'); const targetCol = screen.getByTestId('kanban-column-done'); const dataTransfer = { setData: vi.fn(), getData: (k: string) => { if (k === 'application/x-kanban-entry') return 't-1'; if (k === 'application/x-kanban-source') return 'open'; return ''; }, types: ['application/x-kanban-entry', 'application/x-kanban-source'], effectAllowed: '', dropEffect: '', }; fireEvent.dragStart(card, { dataTransfer }); fireEvent.dragOver(targetCol, { dataTransfer }); fireEvent.drop(targetCol, { dataTransfer }); expect(onMove).toHaveBeenCalledTimes(1); const [movedEntry, target] = onMove.mock.calls[0]; expect(movedEntry.id).toBe('t-1'); expect(target).toBe('done'); }); it('clicking a card fires onSelect', () => { const onSelect = vi.fn(); render(); fireEvent.click(screen.getByTestId('kanban-card-t-2')); expect(onSelect).toHaveBeenCalledWith(expect.objectContaining({ id: 't-2' })); }); });