test(260924-i8v): RED fuer Titel und Serverauswahl der Proxmox-Kachel
- Auswahl-Bauteil: Reihenfolge nach position, Produktwort, Aufraeumen geloeschter Kennungen - Einstellungsformular: Laden, Fehler, Leer, onChange fuer Titel und Auswahl - Einstellungsbereich: Zweig proxmox mit Titel-Zusatz in der Kopfzeile - Kachel im Bearbeitungsmodus: entprellter Titel, Auswahl statt Liste, schliesst beim Verlassen Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,12 @@
|
|||||||
import { act, cleanup, render as rtlRender, screen, waitFor, within } from '@testing-library/react';
|
import {
|
||||||
|
act,
|
||||||
|
cleanup,
|
||||||
|
fireEvent,
|
||||||
|
render as rtlRender,
|
||||||
|
screen,
|
||||||
|
waitFor,
|
||||||
|
within,
|
||||||
|
} from '@testing-library/react';
|
||||||
import { NextIntlClientProvider } from 'next-intl';
|
import { NextIntlClientProvider } from 'next-intl';
|
||||||
import type { ReactElement } from 'react';
|
import type { ReactElement } from 'react';
|
||||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||||
@@ -37,6 +45,11 @@ vi.mock('next/link', () => ({
|
|||||||
),
|
),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const mockUpdateWidgetConfig = vi.fn();
|
||||||
|
vi.mock('@/lib/dashboard-api', () => ({
|
||||||
|
updateWidgetConfig: (...args: unknown[]) => mockUpdateWidgetConfig(...args),
|
||||||
|
}));
|
||||||
|
|
||||||
function mockUser(user: { role: 'SUPER_ADMIN' | 'ADMIN' | 'USER' } | null) {
|
function mockUser(user: { role: 'SUPER_ADMIN' | 'ADMIN' | 'USER' } | null) {
|
||||||
mockAuthStore.mockImplementation((selector: (state: { user: typeof user }) => unknown) =>
|
mockAuthStore.mockImplementation((selector: (state: { user: typeof user }) => unknown) =>
|
||||||
selector({ user }),
|
selector({ user }),
|
||||||
@@ -521,3 +534,109 @@ describe('ProxmoxWidget: Minutentakt (quick-260924-i8v, Aufgabe 2)', () => {
|
|||||||
expect(screen.queryByText('Die Serverliste konnte nicht geladen werden.')).toBeNull();
|
expect(screen.queryByText('Die Serverliste konnte nicht geladen werden.')).toBeNull();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('ProxmoxWidget: Bearbeitungsmodus mit Titel und Serverauswahl (quick-260924-i8v, Aufgabe 3)', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mockUpdateWidgetConfig.mockResolvedValue(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Titelfeld speichert entprellt nach 1500 ms per updateWidgetConfig({ title })', async () => {
|
||||||
|
mockListServers.mockResolvedValue([makeServer('ok')]);
|
||||||
|
await renderWidget({ isEditMode: true, config: { title: 'Alt' } });
|
||||||
|
await screen.findByTestId('proxmox-summary');
|
||||||
|
|
||||||
|
const input = screen.getByLabelText('Titel') as HTMLInputElement;
|
||||||
|
expect(input.value).toBe('Alt');
|
||||||
|
expect(input).toHaveAttribute('placeholder', 'Titel (optional)');
|
||||||
|
expect(input).toHaveClass('widgetNoDrag');
|
||||||
|
|
||||||
|
vi.useFakeTimers({ toFake: ['setTimeout', 'clearTimeout'] });
|
||||||
|
try {
|
||||||
|
fireEvent.change(input, { target: { value: 'N' } });
|
||||||
|
fireEvent.change(input, { target: { value: 'Neu' } });
|
||||||
|
vi.advanceTimersByTime(1499);
|
||||||
|
expect(mockUpdateWidgetConfig).not.toHaveBeenCalled();
|
||||||
|
vi.advanceTimersByTime(1);
|
||||||
|
expect(mockUpdateWidgetConfig).toHaveBeenCalledTimes(1);
|
||||||
|
expect(mockUpdateWidgetConfig).toHaveBeenCalledWith('w-1', { title: 'Neu' });
|
||||||
|
} finally {
|
||||||
|
vi.useRealTimers();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('im Bearbeitungsmodus steht die Kopfzeile auch ohne Titel, mit Abstand zur Griffleiste', async () => {
|
||||||
|
mockListServers.mockResolvedValue([makeServer('ok')]);
|
||||||
|
const { container } = await renderWidget({ isEditMode: true });
|
||||||
|
await screen.findByTestId('proxmox-summary');
|
||||||
|
|
||||||
|
expect(screen.getByLabelText('Titel')).toBeInTheDocument();
|
||||||
|
expect(screen.queryByRole('heading')).toBeNull();
|
||||||
|
expect(container.querySelector('[data-testid="proxmox-widget"]')).toHaveClass('pt-5');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('„Server auswählen“ oeffnet die Auswahl an Stelle der Liste; eine Aenderung speichert sofort und filtert', async () => {
|
||||||
|
mockListServers.mockResolvedValue([
|
||||||
|
makeServer('ok', { id: 'a', name: 'pve-a', position: 0 }),
|
||||||
|
makeServer('down', { id: 'b', name: 'pve-b', position: 1 }),
|
||||||
|
]);
|
||||||
|
await renderWidget({ isEditMode: true });
|
||||||
|
expect(await screen.findByTestId('proxmox-summary')).toHaveTextContent('1 nicht erreichbar');
|
||||||
|
|
||||||
|
const toggle = screen.getByRole('button', { name: 'Server auswählen' });
|
||||||
|
expect(toggle).toHaveAttribute('aria-expanded', 'false');
|
||||||
|
expect(toggle).toHaveAttribute('data-no-drag');
|
||||||
|
fireEvent.click(toggle);
|
||||||
|
expect(toggle).toHaveAttribute('aria-expanded', 'true');
|
||||||
|
|
||||||
|
expect(screen.queryByTestId('proxmox-list')).toBeNull();
|
||||||
|
const group = screen.getByRole('group', { name: 'Angezeigte Server' });
|
||||||
|
expect(group.closest('.widgetNoDrag')).not.toBeNull();
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByRole('checkbox', { name: /pve-a/ }));
|
||||||
|
|
||||||
|
expect(mockUpdateWidgetConfig).toHaveBeenCalledWith('w-1', { serverIds: ['a'] });
|
||||||
|
expect(screen.getByTestId('proxmox-summary')).toHaveTextContent('Alles in Ordnung');
|
||||||
|
// Kein zusaetzlicher Abruf fuer die Auswahl
|
||||||
|
expect(mockListServers).toHaveBeenCalledTimes(1);
|
||||||
|
expect(mockPollServer).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('die Auswahl bekommt die ungefilterte Liste', async () => {
|
||||||
|
mockListServers.mockResolvedValue([
|
||||||
|
makeServer('ok', { id: 'a', name: 'pve-a' }),
|
||||||
|
makeServer('ok', { id: 'b', name: 'pve-b' }),
|
||||||
|
]);
|
||||||
|
await renderWidget({ isEditMode: true, config: { serverIds: ['a'] } });
|
||||||
|
await screen.findByTestId('proxmox-summary');
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByRole('button', { name: 'Server auswählen' }));
|
||||||
|
|
||||||
|
expect(screen.getByRole('checkbox', { name: /pve-a/ })).toBeChecked();
|
||||||
|
expect(screen.getByRole('checkbox', { name: /pve-b/ })).not.toBeChecked();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Verlassen des Bearbeitungsmodus schliesst die Auswahl', async () => {
|
||||||
|
mockListServers.mockResolvedValue([makeServer('ok')]);
|
||||||
|
const { ProxmoxWidget } = await import('./proxmox-widget');
|
||||||
|
const ui = (isEditMode: boolean) => (
|
||||||
|
<NextIntlClientProvider locale="de" messages={de} timeZone="Europe/Berlin">
|
||||||
|
<ProxmoxWidget instanceId="w-1" config={{}} isEditMode={isEditMode} />
|
||||||
|
</NextIntlClientProvider>
|
||||||
|
);
|
||||||
|
const { rerender } = rtlRender(ui(true));
|
||||||
|
await screen.findByTestId('proxmox-summary');
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByRole('button', { name: 'Server auswählen' }));
|
||||||
|
expect(screen.getByRole('group', { name: 'Angezeigte Server' })).toBeInTheDocument();
|
||||||
|
|
||||||
|
rerender(ui(false));
|
||||||
|
expect(screen.queryByRole('group', { name: 'Angezeigte Server' })).toBeNull();
|
||||||
|
expect(screen.getByTestId('proxmox-list')).toBeInTheDocument();
|
||||||
|
|
||||||
|
rerender(ui(true));
|
||||||
|
expect(screen.getByRole('button', { name: 'Server auswählen' })).toHaveAttribute(
|
||||||
|
'aria-expanded',
|
||||||
|
'false',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
import { cleanup, fireEvent, render as rtlRender, screen } from '@testing-library/react';
|
||||||
|
import { NextIntlClientProvider } from 'next-intl';
|
||||||
|
import type { ReactElement } from 'react';
|
||||||
|
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||||
|
import type { ProxmoxProductType, ProxmoxServer } from '@/lib/proxmox-api';
|
||||||
|
import de from '@/messages/de.json';
|
||||||
|
import { ProxmoxServerPicker } from './proxmox-server-picker';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auswahl-Bauteil der Proxmox-Kachel (quick-260924-i8v) — gemeinsam fuer die
|
||||||
|
* Kachel im Bearbeitungsmodus und Einstellungen > Dashboard.
|
||||||
|
*/
|
||||||
|
function render(ui: ReactElement) {
|
||||||
|
return rtlRender(
|
||||||
|
<NextIntlClientProvider locale="de" messages={de} timeZone="Europe/Berlin">
|
||||||
|
{ui}
|
||||||
|
</NextIntlClientProvider>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function server(id: string, productType: ProxmoxProductType, position: number): ProxmoxServer {
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
tenantId: 't1',
|
||||||
|
name: id,
|
||||||
|
productType,
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Absichtlich NICHT nach position geliefert.
|
||||||
|
const SERVERS = [server('pmg-1', 'pmg', 2), server('pve-1', 'pve', 0), server('pbs-1', 'pbs', 1)];
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
cleanup();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('ProxmoxServerPicker (quick-260924-i8v)', () => {
|
||||||
|
it('zeigt je Server ein Kaestchen, sortiert nach position, mit Produktwort', () => {
|
||||||
|
render(<ProxmoxServerPicker servers={SERVERS} selectedIds={[]} onChange={vi.fn()} />);
|
||||||
|
|
||||||
|
const boxes = screen.getAllByRole('checkbox');
|
||||||
|
expect(boxes.map((b) => b.getAttribute('value'))).toEqual(['pve-1', 'pbs-1', 'pmg-1']);
|
||||||
|
expect(screen.getByRole('checkbox', { name: /pve-1.*Virtualisierung/ })).toBeInTheDocument();
|
||||||
|
expect(screen.getByRole('checkbox', { name: /pbs-1.*Datensicherung/ })).toBeInTheDocument();
|
||||||
|
expect(screen.getByRole('checkbox', { name: /pmg-1.*Mail-Gateway/ })).toBeInTheDocument();
|
||||||
|
expect(screen.getByRole('group', { name: 'Angezeigte Server' })).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('ausgewaehlte Kennungen sind angehakt', () => {
|
||||||
|
render(<ProxmoxServerPicker servers={SERVERS} selectedIds={['pbs-1']} onChange={vi.fn()} />);
|
||||||
|
|
||||||
|
expect(screen.getByRole('checkbox', { name: /pbs-1/ })).toBeChecked();
|
||||||
|
expect(screen.getByRole('checkbox', { name: /pve-1/ })).not.toBeChecked();
|
||||||
|
expect(screen.getByRole('checkbox', { name: /pmg-1/ })).not.toBeChecked();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Anhaken liefert die neue Liste in Listenreihenfolge', () => {
|
||||||
|
const onChange = vi.fn();
|
||||||
|
render(<ProxmoxServerPicker servers={SERVERS} selectedIds={['pmg-1']} onChange={onChange} />);
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByRole('checkbox', { name: /pve-1/ }));
|
||||||
|
|
||||||
|
expect(onChange).toHaveBeenCalledWith(['pve-1', 'pmg-1']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Kennungen geloeschter Server fallen bei jeder Aenderung heraus', () => {
|
||||||
|
const onChange = vi.fn();
|
||||||
|
render(
|
||||||
|
<ProxmoxServerPicker
|
||||||
|
servers={SERVERS}
|
||||||
|
selectedIds={['geloescht', 'pbs-1']}
|
||||||
|
onChange={onChange}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByRole('checkbox', { name: /pmg-1/ }));
|
||||||
|
|
||||||
|
expect(onChange).toHaveBeenCalledWith(['pbs-1', 'pmg-1']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('alles abhaken ergibt eine leere Liste', () => {
|
||||||
|
const onChange = vi.fn();
|
||||||
|
render(<ProxmoxServerPicker servers={SERVERS} selectedIds={['pve-1']} onChange={onChange} />);
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByRole('checkbox', { name: /pve-1/ }));
|
||||||
|
|
||||||
|
expect(onChange).toHaveBeenCalledWith([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('der Hinweis „Ohne Auswahl zeigt die Kachel alle Server.“ steht sichtbar da', () => {
|
||||||
|
render(<ProxmoxServerPicker servers={SERVERS} selectedIds={[]} onChange={vi.fn()} />);
|
||||||
|
|
||||||
|
expect(screen.getByText('Ohne Auswahl zeigt die Kachel alle Server.')).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('zwei Instanzen erzeugen eindeutige Feldkennungen', () => {
|
||||||
|
render(
|
||||||
|
<>
|
||||||
|
<ProxmoxServerPicker servers={SERVERS} selectedIds={[]} onChange={vi.fn()} />
|
||||||
|
<ProxmoxServerPicker servers={SERVERS} selectedIds={[]} onChange={vi.fn()} />
|
||||||
|
</>,
|
||||||
|
);
|
||||||
|
|
||||||
|
const ids = screen.getAllByRole('checkbox').map((b) => b.id);
|
||||||
|
expect(new Set(ids).size).toBe(ids.length);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
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(
|
||||||
|
<NextIntlClientProvider locale="de" messages={de} timeZone="Europe/Berlin">
|
||||||
|
{ui}
|
||||||
|
</NextIntlClientProvider>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(
|
||||||
|
<ProxmoxWidgetConfigForm
|
||||||
|
config={{ title: 'Rechenzentrum', serverIds: ['pve-b'] }}
|
||||||
|
onChange={vi.fn()}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
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(<ProxmoxWidgetConfigForm config={{}} onChange={vi.fn()} />);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await screen.findByText('Die Serverliste konnte nicht geladen werden.'),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Leersatz ohne Server', async () => {
|
||||||
|
mockListServers.mockResolvedValue([]);
|
||||||
|
render(<ProxmoxWidgetConfigForm config={{}} onChange={vi.fn()} />);
|
||||||
|
|
||||||
|
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(<ProxmoxWidgetConfigForm config={{}} onChange={onChange} />);
|
||||||
|
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(<ProxmoxWidgetConfigForm config={{ serverIds: ['pve-a'] }} onChange={onChange} />);
|
||||||
|
|
||||||
|
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(<ProxmoxWidgetConfigForm config={{}} onChange={vi.fn()} />);
|
||||||
|
|
||||||
|
await screen.findByRole('checkbox');
|
||||||
|
await waitFor(() => expect(mockListServers).toHaveBeenCalledTimes(1));
|
||||||
|
expect(mockPollServer).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -40,6 +40,15 @@ vi.mock('@/components/settings/search-provider-form', () => ({
|
|||||||
SearchProviderForm: () => null,
|
SearchProviderForm: () => null,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// quick-260924-i8v: das Proxmox-Formular laedt die Serverliste; `pollServer`
|
||||||
|
// nur als Spion (T-I8V-02).
|
||||||
|
const mockListServers = vi.fn();
|
||||||
|
const mockPollServer = vi.fn();
|
||||||
|
vi.mock('@/lib/proxmox-api', () => ({
|
||||||
|
listServers: (...args: unknown[]) => mockListServers(...args),
|
||||||
|
pollServer: (...args: unknown[]) => mockPollServer(...args),
|
||||||
|
}));
|
||||||
|
|
||||||
const clockTexts = (de as { widgets: { clock: Record<string, string> } }).widgets.clock;
|
const clockTexts = (de as { widgets: { clock: Record<string, string> } }).widgets.clock;
|
||||||
const cal = (de as { widgets: { calendar: Record<string, string> } }).widgets.calendar;
|
const cal = (de as { widgets: { calendar: Record<string, string> } }).widgets.calendar;
|
||||||
|
|
||||||
@@ -285,3 +294,42 @@ describe('WidgetSettingsPanel — Bilderrahmen-Kopfzeile (Kosmetik nach quick-26
|
|||||||
expect(screen.getByRole('button', { name: /Bilderrahmen #3/ })).not.toHaveTextContent('—');
|
expect(screen.getByRole('button', { name: /Bilderrahmen #3/ })).not.toHaveTextContent('—');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('WidgetSettingsPanel — Proxmox (quick-260924-i8v)', () => {
|
||||||
|
it('Test PX1: der Zweig rendert das Proxmox-Formular, Kopfzeile zeigt "— Titel", Auswahl ruft updateWidgetConfig/onWidgetUpdate', async () => {
|
||||||
|
mockListServers.mockResolvedValue([
|
||||||
|
{
|
||||||
|
id: 'srv-a',
|
||||||
|
name: 'pve-a',
|
||||||
|
productType: 'pve',
|
||||||
|
position: 0,
|
||||||
|
isActive: true,
|
||||||
|
status: null,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const onWidgetUpdate = vi.fn();
|
||||||
|
const widget = { id: 'px1', widgetType: 'proxmox', config: { title: 'Rechenzentrum' } };
|
||||||
|
render(<WidgetSettingsPanel widgets={[widget]} onWidgetUpdate={onWidgetUpdate} />);
|
||||||
|
|
||||||
|
const header = screen.getByRole('button', { name: /Proxmox #1/ });
|
||||||
|
expect(header).toHaveTextContent('— Rechenzentrum');
|
||||||
|
fireEvent.click(header);
|
||||||
|
|
||||||
|
expect((screen.getByLabelText('Titel') as HTMLInputElement).value).toBe('Rechenzentrum');
|
||||||
|
fireEvent.click(await screen.findByRole('checkbox', { name: /pve-a/ }));
|
||||||
|
|
||||||
|
await vi.waitFor(() =>
|
||||||
|
expect(onWidgetUpdate).toHaveBeenCalledWith('px1', { serverIds: ['srv-a'] }),
|
||||||
|
);
|
||||||
|
expect(updateWidgetConfig).toHaveBeenCalledWith('px1', { serverIds: ['srv-a'] });
|
||||||
|
expect(mockPollServer).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test PX2: ohne Titel kein Zusatz in der Kopfzeile', () => {
|
||||||
|
mockListServers.mockResolvedValue([]);
|
||||||
|
const widget = { id: 'px2', widgetType: 'proxmox', config: {} };
|
||||||
|
render(<WidgetSettingsPanel widgets={[widget]} onWidgetUpdate={vi.fn()} />);
|
||||||
|
|
||||||
|
expect(screen.getByRole('button', { name: /Proxmox #1/ })).not.toHaveTextContent('—');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user