From 0f5f1206af7a812099876ab530d7b3a6cbf02d33 Mon Sep 17 00:00:00 2001
From: quality <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Date: Sat, 17 Oct 2026 22:31:33 -0400
Subject: [PATCH] test: cover DocPage routeMap miss and LanguageSwitcher
navigation error arm
Two reachable branches in the docs app had no test:
- getPageContent in src/app/docs/[...slug]/page.tsx: a slug present in
buildPageMap's routeMap whose mapped file is on disk in neither the
project content directory nor the shared docs/content root must fall
through to null so DocPage calls notFound(). No committed nav entry
points at a missing file, so the route is injected by wrapping
buildPageMap in the test.
- LanguageSwitcher.handleLanguageChange: when router.replace throws, the
error is logged, the dropdown stays open and the transitioning state is
still cleared by finally.
Branch coverage for the [...slug] page rises from 84.88% to 87.2% and
the page's last uncovered line (207) is now exercised.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: quality <280983584+hivecommons-hive[bot]@users.noreply.github.com>
---
.../LanguageSwitcher.behavior.test.tsx | 27 +++++++
.../docs-slug-page.routemap-miss.test.tsx | 74 +++++++++++++++++++
2 files changed, 101 insertions(+)
create mode 100644 src/__tests__/docs-slug-page.routemap-miss.test.tsx
diff --git a/src/__tests__/LanguageSwitcher.behavior.test.tsx b/src/__tests__/LanguageSwitcher.behavior.test.tsx
index 8274ba1..7270287 100644
--- a/src/__tests__/LanguageSwitcher.behavior.test.tsx
+++ b/src/__tests__/LanguageSwitcher.behavior.test.tsx
@@ -124,6 +124,33 @@ describe("LanguageSwitcher dropdown variant", () => {
expect(screen.queryByRole("listbox")).toBeNull();
});
+ it("logs and recovers when navigation throws, leaving the menu open", async () => {
+ const boom = new Error("router exploded");
+ replaceMock.mockImplementation(() => {
+ throw boom;
+ });
+ const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
+
+ try {
+ render();
+ fireEvent.click(trigger());
+ fireEvent.click(screen.getByText(localeNames.ja));
+
+ await act(async () => {
+ await vi.advanceTimersByTimeAsync(200);
+ });
+
+ expect(replaceMock).toHaveBeenCalledTimes(1);
+ expect(errorSpy).toHaveBeenCalledWith("Failed to change language:", boom);
+ // The catch arm skips setIsOpen(false); finally still clears the spinner.
+ expect(screen.getByRole("listbox")).toBeTruthy();
+ expect(screen.queryByText("Switching...")).toBeNull();
+ expect(trigger().hasAttribute("disabled")).toBe(false);
+ } finally {
+ errorSpy.mockRestore();
+ }
+ });
+
it("closes without navigating when the current locale is re-selected", () => {
render();
fireEvent.click(trigger());
diff --git a/src/__tests__/docs-slug-page.routemap-miss.test.tsx b/src/__tests__/docs-slug-page.routemap-miss.test.tsx
new file mode 100644
index 0000000..95f12d0
--- /dev/null
+++ b/src/__tests__/docs-slug-page.routemap-miss.test.tsx
@@ -0,0 +1,74 @@
+/**
+ * Covers the last arm of getPageContent in src/app/docs/[...slug]/page.tsx:
+ * the slug is a nav-generated route (present in buildPageMap's routeMap) but
+ * the mapped file exists in neither the project content directory nor the
+ * shared docs/content root. The lookup must fall through to `return null`,
+ * which DocPage turns into notFound(), rather than throwing or rendering an
+ * empty page.
+ *
+ * No committed nav entry points at a missing file (the sync step would fail
+ * the build), so the route is injected by wrapping buildPageMap.
+ */
+import { describe, expect, it, vi } from "vitest";
+
+const NOT_FOUND = new Error("NEXT_NOT_FOUND (test sentinel)");
+vi.mock("next/navigation", async importOriginal => {
+ const actual = await importOriginal();
+ return {
+ ...actual,
+ usePathname: () => "/docs/hive/ghost-route",
+ notFound: () => {
+ throw NOT_FOUND;
+ },
+ };
+});
+
+const GHOST_ROUTE = "ghost-route";
+const GHOST_FILE = "ghost/not-on-disk.md";
+
+const { buildPageMapSpy } = vi.hoisted(() => ({ buildPageMapSpy: vi.fn() }));
+vi.mock("../app/docs/page-map", async importOriginal => {
+ const actual = await importOriginal();
+ buildPageMapSpy.mockImplementation(
+ (projectId?: Parameters[0]) => {
+ const real = actual.buildPageMap(projectId);
+ return {
+ ...real,
+ routeMap: { ...real.routeMap, [GHOST_ROUTE]: GHOST_FILE },
+ };
+ }
+ );
+ return { ...actual, buildPageMap: buildPageMapSpy };
+});
+
+const { compileMdx } = vi.hoisted(() => ({
+ compileMdx: vi.fn(() => {
+ throw new Error(
+ "compileMdx must not be called when no source file resolves"
+ );
+ }),
+}));
+vi.mock("nextra/compile", () => ({ compileMdx }));
+
+import fs from "fs";
+import path from "path";
+import { docsContentPath, getContentPath } from "../app/docs/page-map";
+import DocPage from "../app/docs/[...slug]/page";
+
+describe("getPageContent — routeMap hit whose file is missing on disk", () => {
+ it("404s instead of rendering when the mapped file is absent from both content roots", async () => {
+ expect(fs.existsSync(path.join(getContentPath("hive"), GHOST_FILE))).toBe(
+ false
+ );
+ expect(fs.existsSync(path.join(docsContentPath, GHOST_FILE))).toBe(false);
+
+ await expect(
+ DocPage({ params: Promise.resolve({ slug: ["hive", GHOST_ROUTE] }) })
+ ).rejects.toBe(NOT_FOUND);
+
+ // The routeMap was consulted for this project and the miss never reached
+ // the MDX compiler.
+ expect(buildPageMapSpy).toHaveBeenCalledWith("hive");
+ expect(compileMdx).not.toHaveBeenCalled();
+ });
+});