import { describe, expect, it, vi } from "vitest"; import { renderToStaticMarkup } from "react-dom/server"; // The section components rely on TanStack Query, the auth hook, and a // few API routes. Stub everything at the module boundary so we can // SSR-render each section in isolation and assert the heading paints. // // This is intentionally a smoke test — covering the loading branch // (most sections paint a Loader2 + label until data arrives) is enough // to guarantee the dynamic-route renderer doesn't blow up when it // imports a section. vi.mock("next/navigation", () => ({ useRouter: () => ({ push: vi.fn(), replace: vi.fn() }), usePathname: () => "/admin/system-status", })); vi.mock("@tanstack/react-query", () => ({ useQuery: () => ({ data: null, isLoading: false, refetch: vi.fn() }), useQueryClient: () => ({ invalidateQueries: vi.fn() }), useMutation: () => ({ mutate: vi.fn(), isPending: false, isError: false, error: null, }), })); vi.mock("@/hooks/use-auth", () => ({ useAuth: () => ({ user: { id: "u1", username: "marc", email: "marc@example.com", role: "ADMIN", }, isAuthenticated: true, isLoading: false, refetch: vi.fn(), }), })); import { I18nProvider } from "@/lib/i18n/context"; import { ADMIN_SECTION_SLUGS } from "../section-slugs"; import { ApiTokenOverviewSection } from "../api-token-overview-section"; import { BackupsSection } from "../backups-section"; import { DangerZoneSection } from "../danger-zone-section"; import { FeedbackInboxSection } from "../feedback-inbox-section"; import { GeneralSettingsSection } from "../general-settings-section"; import { IntegrationsGroupSection } from "../integrations-group-section"; import { LoginOverviewSection } from "../login-overview-section"; import { RemindersSection } from "../reminders-section"; import { ServicesSection } from "../services-section"; import { SystemStatusSection } from "../system-status-section"; import { UserManagementSection } from "../user-management-section"; function render(node: React.ReactElement) { return renderToStaticMarkup( {node}, ); } describe("admin sections — SSR smoke", () => { it("every slug in `ADMIN_SECTION_SLUGS` has a wired component", () => { // Renderer-side parity: if a slug is added to the list but no // matching case is added in `renderer.tsx`, the switch's `never` // exhaustiveness guard fails type-check. This test mirrors that // guarantee at runtime so a slug typo (or stale list) is caught // even without `tsc`. expect(ADMIN_SECTION_SLUGS).toContain("system-status"); expect(ADMIN_SECTION_SLUGS).toContain("backups"); expect(ADMIN_SECTION_SLUGS).toContain("users"); expect(ADMIN_SECTION_SLUGS).toContain("danger-zone"); }); it(" renders", () => { const html = render(); expect(html).toContain("System"); }); it(" renders", () => { const html = render(); expect(html).toContain("Allow registration"); }); it(" renders", () => { const html = render(); expect(html).toContain("Telegram"); }); it(" renders all four sub-sections", () => { const html = render(); expect(html).toContain("Umami"); expect(html).toContain("Glitchtip"); expect(html).toContain("Web Push"); }); it(" renders", () => { const html = render(); expect(html).toContain("Feedback"); }); it(" renders", () => { const html = render(); expect(html).toContain("Medication Reminders"); }); it(" renders with filter pills", () => { const html = render(); expect(html).toContain("User Management"); // Filter pills painted from i18n expect(html).toContain("All"); expect(html).toContain("Admins"); }); it(" renders", () => { const html = render(); expect(html).toContain("API Tokens"); }); it(" renders", () => { const html = render(); expect(html).toContain("Login Overview"); }); it(" renders heading + run-now button", () => { const html = render(); expect(html).toContain("Backups"); expect(html).toContain("Backup now"); }); it(" renders", () => { const html = render(); expect(html).toContain("Danger Zone"); }); });