From 069d5a79257590a3d2f6ecd45a2a08c1a3cc9984 Mon Sep 17 00:00:00 2001 From: Ravi Tharuma <25951435+RaviTharuma@users.noreply.github.com> Date: Thu, 23 Jul 2026 16:06:59 +0200 Subject: [PATCH] fix(dashboard): stop sidebar RSC prefetch storms (#8292) * fix(dashboard): disable sidebar route prefetch Co-Authored-By: Claude * test(dashboard): cover sidebar prefetch traffic Co-Authored-By: Claude --------- Co-authored-by: Ravi Tharuma Co-authored-by: Claude --- src/shared/components/Sidebar.tsx | 2 ++ tests/e2e/navigation.spec.ts | 25 +++++++++++++++++++ .../unit/sidebar-prefetch-policy-8281.test.ts | 17 +++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 tests/unit/sidebar-prefetch-policy-8281.test.ts diff --git a/src/shared/components/Sidebar.tsx b/src/shared/components/Sidebar.tsx index ed2188055e..45e7af3231 100644 --- a/src/shared/components/Sidebar.tsx +++ b/src/shared/components/Sidebar.tsx @@ -431,6 +431,7 @@ export default function Sidebar({
diff --git a/tests/e2e/navigation.spec.ts b/tests/e2e/navigation.spec.ts index 0f23b14bff..76db5db458 100644 --- a/tests/e2e/navigation.spec.ts +++ b/tests/e2e/navigation.spec.ts @@ -1,4 +1,5 @@ import { test, expect } from "@playwright/test"; +import { gotoDashboardRoute } from "./helpers/dashboardAuth"; test.describe("Dashboard Navigation", () => { test("redirects unauthenticated user to /login", async ({ page }) => { @@ -10,6 +11,30 @@ test.describe("Dashboard Navigation", () => { expect(url).toMatch(/\/(login|dashboard)/); }); + test("does not prefetch dashboard routes and preserves client navigation", async ({ page }) => { + const speculativeRequests: string[] = []; + + page.on("request", (request) => { + const headers = request.headers(); + const isRscPrefetch = + headers.rsc === "1" && + (headers["next-router-prefetch"] === "1" || + headers.purpose?.toLowerCase().includes("prefetch") || + headers["sec-purpose"]?.toLowerCase().includes("prefetch")); + + if (isRscPrefetch) speculativeRequests.push(request.url()); + }); + + await gotoDashboardRoute(page, "/home"); + await expect(page.getByRole("link", { name: /providers/i }).first()).toBeVisible(); + await page.waitForTimeout(500); + + expect(speculativeRequests).toEqual([]); + + await page.getByRole("link", { name: /providers/i }).first().click(); + await expect(page).toHaveURL(/\/dashboard\/providers/); + }); + test("login page renders with form elements", async ({ page }) => { await page.goto("/login"); // Should show some form of authentication UI diff --git a/tests/unit/sidebar-prefetch-policy-8281.test.ts b/tests/unit/sidebar-prefetch-policy-8281.test.ts new file mode 100644 index 0000000000..02c170cc71 --- /dev/null +++ b/tests/unit/sidebar-prefetch-policy-8281.test.ts @@ -0,0 +1,17 @@ +import assert from "node:assert/strict"; +import { readFile } from "node:fs/promises"; +import test from "node:test"; + +const SIDEBAR = "src/shared/components/Sidebar.tsx"; + +test("#8281: dashboard navigation opts out of automatic route prefetch", async () => { + const source = await readFile(SIDEBAR, "utf8"); + + const internalLink = source.match(//); + assert.ok(internalLink, "expected the sidebar's internal navigation Link"); + assert.match(internalLink[0], /prefetch=\{false\}/); + + const logoLink = source.match(//); + assert.ok(logoLink, "expected the sidebar logo home Link"); + assert.match(logoLink[0], /prefetch=\{false\}/); +});