diff --git a/web/src/components/Breadcrumbs.tsx b/web/src/components/Breadcrumbs.tsx index 273e70a..69e78f6 100644 --- a/web/src/components/Breadcrumbs.tsx +++ b/web/src/components/Breadcrumbs.tsx @@ -20,7 +20,7 @@ // upgrading to data-router-driven crumbs is a future task once the // router migration ships. -import { Link, useLocation } from 'react-router-dom'; +import { Link, useLocation, useInRouterContext } from 'react-router-dom'; import { ChevronRight } from 'lucide-react'; // pathSegmentLabels — map first-segment URL keys to human labels. @@ -126,7 +126,19 @@ function looksLikeID(s: string): boolean { return s.includes('-') || /^[a-f0-9]{8,}$/i.test(s); } +// Breadcrumbs is the public entry. Defensive against missing Router +// context (a test that mounts a PageHeader without a +// wrapper used to crash here). useLocation() throws an invariant +// error if there's no Router; gate it behind useInRouterContext() +// + render the actual logic in a sibling so useLocation() is only +// called when we know the context is present. export default function Breadcrumbs() { + const inRouter = useInRouterContext(); + if (!inRouter) return null; + return ; +} + +function BreadcrumbsInner() { const { pathname } = useLocation(); const crumbs = crumbsFor(pathname); diff --git a/web/src/pages/auth/UsersPage.test.tsx b/web/src/pages/auth/UsersPage.test.tsx index 2b86e4c..fab106e 100644 --- a/web/src/pages/auth/UsersPage.test.tsx +++ b/web/src/pages/auth/UsersPage.test.tsx @@ -1,6 +1,7 @@ import { describe, it, expect, vi, beforeEach } from 'vitest'; import { render, screen, fireEvent, waitFor, cleanup } from '@testing-library/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { MemoryRouter } from 'react-router-dom'; import type { ReactNode } from 'react'; // ============================================================================= @@ -29,8 +30,13 @@ function renderWithProviders(ui: ReactNode) { const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false }, mutations: { retry: false } }, }); + // MemoryRouter required because PageHeader now renders Breadcrumbs + // (Phase 3 UX-M5), which calls useLocation() and throws when there + // is no Router context in the tree. return render( - {ui}, + + {ui} + , ); }