import { cleanup, fireEvent, render as rtlRender, screen, waitFor } from '@testing-library/react'; import { NextIntlClientProvider } from 'next-intl'; import type { ReactElement } from 'react'; import { afterEach, describe, expect, it, vi } from 'vitest'; import type { ProxmoxServer } from '@/lib/proxmox-api'; import de from '@/messages/de.json'; /** * Einstellungsformular der Proxmox-Kachel (quick-260924-i8v) fuer * Einstellungen > Dashboard: Titel und Serverauswahl. */ function render(ui: ReactElement) { return rtlRender( {ui} , ); } // T-I8V-02: `pollServer` nur als Spion — das Formular darf ihn nie rufen. const mockListServers = vi.fn(); const mockPollServer = vi.fn(); vi.mock('@/lib/proxmox-api', () => ({ listServers: (...args: unknown[]) => mockListServers(...args), pollServer: (...args: unknown[]) => mockPollServer(...args), })); import { ProxmoxWidgetConfigForm } from './proxmox-widget-config-form'; function server(id: string, position: number): ProxmoxServer { return { id, tenantId: 't1', name: id, productType: 'pve', baseUrl: 'https://x.intern', authMethod: 'token', tokenId: 'a@pam!b', username: null, tlsRejectUnauthorized: true, isActive: true, pollIntervalMin: 5, position, createdAt: '2026-01-01T00:00:00.000Z', updatedAt: '2026-01-01T00:00:00.000Z', status: null, }; } afterEach(() => { cleanup(); vi.clearAllMocks(); }); describe('ProxmoxWidgetConfigForm (quick-260924-i8v)', () => { it('laedt die Server einmal und zeigt die Auswahl, vorbelegt aus der Konfiguration', async () => { mockListServers.mockResolvedValue([server('pve-a', 0), server('pve-b', 1)]); render( , ); expect(screen.getByText('Lade Serverliste...')).toBeInTheDocument(); expect(await screen.findByRole('checkbox', { name: /pve-b/ })).toBeChecked(); expect(screen.getByRole('checkbox', { name: /pve-a/ })).not.toBeChecked(); expect((screen.getByLabelText('Titel') as HTMLInputElement).value).toBe('Rechenzentrum'); expect(mockListServers).toHaveBeenCalledTimes(1); }); it('Fehlersatz, wenn die Liste nicht geladen werden kann', async () => { mockListServers.mockRejectedValue(new Error('500')); render(); expect( await screen.findByText('Die Serverliste konnte nicht geladen werden.'), ).toBeInTheDocument(); }); it('Leersatz ohne Server', async () => { mockListServers.mockResolvedValue([]); render(); expect(await screen.findByText('Noch kein Proxmox-Server eingetragen.')).toBeInTheDocument(); expect(screen.queryByRole('checkbox')).toBeNull(); }); it('Titelaenderung ruft onChange({ title }) mit dem rohen Tippwert', async () => { mockListServers.mockResolvedValue([server('pve-a', 0)]); const onChange = vi.fn(); render(); await screen.findByRole('checkbox'); fireEvent.change(screen.getByLabelText('Titel'), { target: { value: 'Keller ' } }); expect(onChange).toHaveBeenCalledWith({ title: 'Keller ' }); }); it('Auswahlaenderung ruft onChange({ serverIds })', async () => { mockListServers.mockResolvedValue([server('pve-a', 0), server('pve-b', 1)]); const onChange = vi.fn(); render(); fireEvent.click(await screen.findByRole('checkbox', { name: /pve-b/ })); expect(onChange).toHaveBeenCalledWith({ serverIds: ['pve-a', 'pve-b'] }); }); it('ruft nie die manuelle Abfrage auf (T-I8V-02)', async () => { mockListServers.mockResolvedValue([server('pve-a', 0)]); render(); await screen.findByRole('checkbox'); await waitFor(() => expect(mockListServers).toHaveBeenCalledTimes(1)); expect(mockPollServer).not.toHaveBeenCalled(); }); });