import { cleanup, render, screen, waitFor, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { afterEach, describe, expect, it, vi } from 'vitest'; import { EventsPage } from '../../src/EventsPage'; const items = Array.from({ length: 100 }, (_, index) => ({ id: `event-${String(index + 1).padStart(3, '0')}`, type: index % 2 === 0 ? 'service.down' : 'container.restart', severity: index % 10 === 0 ? 'critical' : index % 3 === 0 ? 'warning' : 'info', entityId: `entity-${String(index % 5).padStart(2, '0')}`, sourceId: 'source-unraid', occurredAt: new Date(Date.UTC(2026, 7, 21, 12, 0, 0) - index * 60_000).toISOString(), receivedAt: new Date(Date.UTC(2026, 7, 21, 12, 0, 5) - index * 60_000).toISOString(), summary: `Gebeurtenis ${String(index + 1).padStart(3, '0')}`, })); afterEach(() => { cleanup(); vi.unstubAllGlobals(); window.history.replaceState({}, '', '/events'); }); function mockEvents(payload = items) { const fetch = vi.fn(async () => new Response(JSON.stringify({ items: payload }), { status: 200, headers: { 'Content-Type': 'application/json' } })); vi.stubGlobal('fetch', fetch); return fetch; } describe('compacte eventtijdlijn', () => { it('houdt honderd events begrensd en pagineert deterministisch met focus', async () => { const fetch = mockEvents(); const user = userEvent.setup(); render(); const list = await screen.findByRole('list', { name: 'Resultaten' }); expect(within(list).getAllByRole('listitem')).toHaveLength(20); expect(within(list).getByText('event-001')).toBeInTheDocument(); expect(within(list).queryByText('event-021')).not.toBeInTheDocument(); const next = screen.getByRole('button', { name: 'Volgende pagina' }); await user.click(next); await waitFor(() => expect(screen.getByText(/Pagina 2 van 5/)).toHaveFocus()); expect(within(list).getByText('event-021')).toBeInTheDocument(); expect(window.location.search).toContain('page=2'); expect(fetch).toHaveBeenCalledTimes(1); }); it('filtert ernst, soort, onderdeel en vrije tekst zonder nieuwe request', async () => { const fetch = mockEvents(); const user = userEvent.setup(); render(); const list = await screen.findByRole('list', { name: 'Resultaten' }); await user.selectOptions(screen.getByLabelText('Ernst'), 'critical'); expect(within(list).getAllByRole('listitem')).toHaveLength(10); await user.selectOptions(screen.getByLabelText('Soort'), 'service.down'); expect(within(list).getAllByRole('listitem')).toHaveLength(10); await user.selectOptions(screen.getByLabelText('Onderdeel'), 'entity-00'); expect(within(list).getAllByRole('listitem')).toHaveLength(10); await user.clear(screen.getByLabelText('Zoeken')); await user.type(screen.getByLabelText('Zoeken'), 'Gebeurtenis 091'); expect(within(list).getAllByRole('listitem')).toHaveLength(1); expect(within(list).getByText('event-091')).toBeInTheDocument(); expect(fetch).toHaveBeenCalledTimes(1); }); it('houdt het kritieke totaal zichtbaar en biedt een herstelbare lege state', async () => { mockEvents(); const user = userEvent.setup(); render(); const critical = await screen.findByRole('button', { name: /Kritieke gebeurtenissen/i }); expect(critical).toHaveTextContent('10'); await user.type(screen.getByLabelText('Zoeken'), 'bestaat-niet'); expect(screen.getByText('Geen gebeurtenissen binnen de huidige filters.')).toBeVisible(); expect(critical).toBeVisible(); await user.click(screen.getByRole('button', { name: 'Alle filters wissen' })); expect(await screen.findByRole('list', { name: 'Resultaten' })).toBeVisible(); }); });