/* @vitest-environment node */ import { describe, it, expect, vi } from "vitest"; import React from "react"; import { renderToString } from "react-dom/server"; /** * Mock `next/link` so this unit test does not depend on the Next.js runtime. * For a server-render smoke test, a minimal replacement is enough. */ vi.mock("next/link", async () => { const ReactNs = await import("react"); const React = ReactNs.default ?? ReactNs; function LinkMock({ href, children, ...props }) { const resolvedHref = typeof href === "string" ? href : href?.pathname ? String(href.pathname) : ""; return React.createElement("a", { href: resolvedHref, ...props }, children); } return { default: LinkMock }; }); /** * Mock `next/image` to avoid Next.js runtime constraints in SSR unit tests * (e.g. width/height enforcement, internal config dependencies). */ vi.mock("next/image", async () => { const ReactNs = await import("react"); const React = ReactNs.default ?? ReactNs; function ImageMock(props) { const { src, alt, width, height, fill, priority, quality, loader, blurDataURL, placeholder, sizes, ...rest } = props || {}; const resolvedSrc = typeof src === "string" ? src : src?.src ? String(src.src) : ""; const imgProps = { src: resolvedSrc, alt: alt || "", ...rest, }; // Only attach width/height if present (fill-mode images won't have them). if (width !== undefined) imgProps.width = width; if (height !== undefined) imgProps.height = height; return React.createElement("img", imgProps); } return { default: ImageMock }; }); /** * AppShell renders TopNav which includes QuickNav (client component). * QuickNav uses next/navigation hooks (useRouter/usePathname). * * In a pure react-dom/server smoke test, we must mock these hooks to avoid * runtime errors and keep this test deterministic. */ vi.mock("next/navigation", () => { return { usePathname: () => "/", useRouter: () => ({ push: () => {}, replace: () => {}, refresh: () => {}, prefetch: () => {}, }), }; }); // Import AFTER the mocks so the module under test uses the mocked Next modules. import AppShell from "./AppShell"; describe("components/app-shell/AppShell", () => { it("renders the shell without crashing and includes key areas", () => { const element = React.createElement( AppShell, null, React.createElement("div", null, "Child content"), ); const html = renderToString(element); // Sidebar placeholder heading (German) expect(html).toContain("Seitenleiste"); // Rendered children expect(html).toContain("Child content"); }); });