import { cleanup, render, screen, waitFor } from '@testing-library/react'; import { afterEach, describe, expect, it, vi } from 'vitest'; import type { ProxmoxServer } from '@/lib/proxmox-api'; // Mock @/lib/proxmox-api — die Seite ruft `listServers` beim Laden auf, // "Jetzt aktualisieren" ruft `pollServer` je Server. const mockListServers = vi.fn(); const mockPollServer = vi.fn(); vi.mock('@/lib/proxmox-api', () => ({ listServers: (...args: unknown[]) => mockListServers(...args), pollServer: (...args: unknown[]) => mockPollServer(...args), })); // Mock the auth store — mirrors settings-roles.test.tsx (selector-passthrough). const mockAuthStore = vi.fn(); vi.mock('@/lib/stores/auth-store', () => ({ useAuthStore: (selector: (state: unknown) => unknown) => mockAuthStore(selector), })); vi.mock('next/link', () => ({ default: ({ href, children, ...rest }: { href: string; children: React.ReactNode }) => ( {children} ), })); vi.mock('next-intl', () => ({ useTranslations: () => (key: string, params?: Record) => { const translations: Record = { title: 'Proxmox', description: 'Zustand Ihrer Proxmox-Server (PVE/PBS/PMG) auf einen Blick.', loading: 'Lade Serverliste...', loadError: 'Die Serverliste konnte nicht geladen werden.', emptyState: 'Noch kein Server eingetragen. Legen Sie in den Moduleinstellungen einen Server an.', 'card.refresh': 'Jetzt aktualisieren', 'card.refreshing': 'Wird aktualisiert...', 'card.settingsLink': 'Zu den Einstellungen', 'card.unknownValue': 'unbekannt', 'card.lastPolledLabel': 'Letzte Abfrage', 'card.notPolledYet': 'Noch keine Abfrage gelaufen. Klicken Sie oben auf „{refreshLabel}“.', 'card.notPolledYetAutomatic': 'Noch keine Abfrage gelaufen. Die Werte erscheinen nach der nächsten automatischen Abfrage.', }; let result = translations[key] ?? key; if (params) { for (const [k, v] of Object.entries(params)) { result = result.replace(`{${k}}`, String(v)); } } return result; }, })); function mockUser(user: { role: 'SUPER_ADMIN' | 'ADMIN' | 'USER' } | null) { mockAuthStore.mockImplementation((selector: (state: { user: typeof user }) => unknown) => selector({ user }), ); } // Ein nie abgefragter Server (wie im Befund-2-Test von ServerCard.test.tsx): // leere Zwischenlagerzeile direkt nach `createServer`. function makeUnpolledServer(overrides: Partial = {}): ProxmoxServer { return { id: 'srv-1', tenantId: 't1', name: 'pve-1', productType: 'pve', baseUrl: 'https://pve.intern', authMethod: 'token', tokenId: 'root@pam!x', username: null, tlsRejectUnauthorized: true, isActive: true, pollIntervalMin: 5, position: 0, createdAt: '2026-01-01T00:00:00.000Z', updatedAt: '2026-01-01T00:00:00.000Z', status: { id: 's1', serverId: 'srv-1', lastPolledAt: null, lastOkAt: null, reachable: false, errorKind: null, errorDetail: null, rawSample: null, updatedAt: '2026-01-01T00:00:00.000Z', metrics: null, }, ...overrides, } as ProxmoxServer; } afterEach(() => { cleanup(); mockListServers.mockReset(); mockPollServer.mockReset(); mockAuthStore.mockReset(); }); describe('ProxmoxPage role gating (260923-le6)', () => { it('Rolle USER: kein Knopf "Jetzt aktualisieren", Karten-Hinweis ist der automatische Text', async () => { mockUser({ role: 'USER' }); mockListServers.mockResolvedValue([makeUnpolledServer()]); const { default: ProxmoxPage } = await import('./page'); render(); await screen.findByText('pve-1'); expect(screen.queryByRole('button', { name: 'Jetzt aktualisieren' })).not.toBeInTheDocument(); expect( screen.getByText( 'Noch keine Abfrage gelaufen. Die Werte erscheinen nach der nächsten automatischen Abfrage.', ), ).toBeInTheDocument(); }); it('kein Benutzer geladen (user: null): kein Knopf', async () => { mockUser(null); mockListServers.mockResolvedValue([makeUnpolledServer()]); const { default: ProxmoxPage } = await import('./page'); render(); await screen.findByText('pve-1'); expect(screen.queryByRole('button', { name: 'Jetzt aktualisieren' })).not.toBeInTheDocument(); }); it('Rolle ADMIN: Knopf sichtbar, Karten-Hinweis ist der Admin-Text mit Knopfverweis', async () => { mockUser({ role: 'ADMIN' }); mockListServers.mockResolvedValue([makeUnpolledServer()]); const { default: ProxmoxPage } = await import('./page'); render(); await screen.findByText('pve-1'); expect(screen.getByRole('button', { name: 'Jetzt aktualisieren' })).toBeInTheDocument(); expect( screen.getByText('Noch keine Abfrage gelaufen. Klicken Sie oben auf „Jetzt aktualisieren“.'), ).toBeInTheDocument(); }); it('Rolle SUPER_ADMIN: Knopf sichtbar', async () => { mockUser({ role: 'SUPER_ADMIN' }); mockListServers.mockResolvedValue([makeUnpolledServer()]); const { default: ProxmoxPage } = await import('./page'); render(); await screen.findByText('pve-1'); expect(screen.getByRole('button', { name: 'Jetzt aktualisieren' })).toBeInTheDocument(); }); it('leere Serverliste bei ADMIN: weiterhin kein Knopf', async () => { mockUser({ role: 'ADMIN' }); mockListServers.mockResolvedValue([]); const { default: ProxmoxPage } = await import('./page'); render(); await waitFor(() => { expect( screen.getByText( 'Noch kein Server eingetragen. Legen Sie in den Moduleinstellungen einen Server an.', ), ).toBeInTheDocument(); }); expect(screen.queryByRole('button', { name: 'Jetzt aktualisieren' })).not.toBeInTheDocument(); }); });