import { describe, it, expect, beforeEach, vi } from 'vitest' import { screen, waitFor } from '@testing-library/react' import { http, HttpResponse } from 'msw' import { server } from '@/test/mocks/server' import { renderWithProviders } from '@/test/utils' import { DashboardPage } from '@/pages/DashboardPage' // Recharts ResponsiveContainer needs ResizeObserver as a proper constructor class ResizeObserverStub { observe() {} unobserve() {} disconnect() {} } vi.stubGlobal('ResizeObserver', ResizeObserverStub) // Mock recharts to avoid SVG rendering issues in jsdom // We render a simplified version that outputs the data as text vi.mock('recharts', async () => { const actual = await vi.importActual('recharts') return { ...actual, ResponsiveContainer: ({ children }: { children: React.ReactNode }) => (
{children}
), PieChart: ({ children }: { children: React.ReactNode }) => (
{children}
), BarChart: ({ children }: { children: React.ReactNode }) => (
{children}
), Pie: ({ data }: { data?: Array<{ name: string; value: number }> }) => (
{data?.map((entry) => ( {entry.name} ))}
), Bar: () =>
, Cell: () =>
, XAxis: () =>
, YAxis: () =>
, CartesianGrid: () =>
, Tooltip: () =>
, Legend: () =>
, } }) describe('DashboardPage', () => { beforeEach(() => { localStorage.setItem('access_token', 'test-token') }) it('renders KPI cards with correct values once loaded', async () => { renderWithProviders() await waitFor(() => { expect(screen.getByText('Fälle gesamt')).toBeInTheDocument() }) // Check all four KPI card titles expect(screen.getByText('Offene ICD')).toBeInTheDocument() expect(screen.getByText('Offene Codierung')).toBeInTheDocument() expect(screen.getByText('Gutachten gesamt')).toBeInTheDocument() // Check KPI values from mockDashboardKPIs (142, 18, 7, 89) expect(screen.getByText('142')).toBeInTheDocument() expect(screen.getByText('18')).toBeInTheDocument() expect(screen.getByText('7')).toBeInTheDocument() expect(screen.getByText('89')).toBeInTheDocument() }) it('shows year selector', async () => { renderWithProviders() // The Select trigger should show the current year const currentYear = new Date().getFullYear() await waitFor(() => { expect(screen.getByText(String(currentYear))).toBeInTheDocument() }) // The heading should be present expect(screen.getByText('Dashboard')).toBeInTheDocument() }) it('shows loading skeleton initially', () => { // Delay the API response so we can observe the loading state server.use( http.get('/api/reports/dashboard', async () => { await new Promise((resolve) => setTimeout(resolve, 500)) return HttpResponse.json({ kpis: {}, weekly: [] }) }), ) renderWithProviders() // During loading, the KPI titles should not be visible yet expect(screen.queryByText('Fälle gesamt')).not.toBeInTheDocument() // The heading is always visible expect(screen.getByText('Dashboard')).toBeInTheDocument() }) it('filters 0-value Fallgruppen from pie chart data', async () => { // The mock data has: onko: 65, ortho: 42, kardio: 20, neuro: 15 // FALLGRUPPEN_LABELS maps onko->Onkologie, kardio->Kardiologie // ortho and neuro are not in FALLGRUPPEN_LABELS so they use the raw key // All values are > 0, so all should appear in the pie chart // sd, intensiv, galle are NOT in mock data, so they should not appear renderWithProviders() await waitFor(() => { expect(screen.getByText('Fälle gesamt')).toBeInTheDocument() }) // The chart section title should appear expect(screen.getByText('Fallgruppen')).toBeInTheDocument() // Onkologie and Kardiologie should appear (mapped from FALLGRUPPEN_LABELS) expect(screen.getByText('Onkologie')).toBeInTheDocument() expect(screen.getByText('Kardiologie')).toBeInTheDocument() // ortho and neuro use raw keys since they are not in FALLGRUPPEN_LABELS expect(screen.getByText('ortho')).toBeInTheDocument() expect(screen.getByText('neuro')).toBeInTheDocument() // Schilddrüse should NOT appear (sd is not in mock data) expect(screen.queryByText('Schilddrüse')).not.toBeInTheDocument() // Intensivmedizin should NOT appear (intensiv is not in mock data) expect(screen.queryByText('Intensivmedizin')).not.toBeInTheDocument() // Gallenblase should NOT appear (galle is not in mock data) expect(screen.queryByText('Gallenblase')).not.toBeInTheDocument() }) it('handles error state when API returns 500', async () => { server.use( http.get('/api/reports/dashboard', () => { return new HttpResponse(null, { status: 500 }) }), ) renderWithProviders() // When data is null and loading is false, it shows the fallback message await waitFor(() => { expect(screen.getByText('Keine Daten verfügbar.')).toBeInTheDocument() }) }) })