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();
});
});