fix(sidebar): top-level nav rendered only dashboardItems[0]

The Search entry added in 1ee3555 was in the array, in the build, and
typed correctly — and never appeared. The top-level nav block rendered
`dashboardItems[0]` with a hardcoded index, so every entry after the
first was silently dropped. Caught when the operator asked where the
link was.

Rendered as a map so appending an entry just works.

Regression test asserts the whole top-level set (Dashboard + Search)
rather than "Search exists", so the next person to append an entry gets
a passing test instead of an invisible link. Verified it fails when the
map is limited back to a single entry while the three pre-existing
sidebar tests keep passing.
This commit is contained in:
Dave 2026-10-14 11:03:04 +02:00
parent 1ee3555239
commit 60ccfa8122
2 changed files with 41 additions and 6 deletions

View file

@ -95,4 +95,31 @@ describe("Sidebar", () => {
expect(ops.queryByText("Stock Orders")).not.toBeInTheDocument();
expect(ops.queryByText("Pricelist")).not.toBeInTheDocument();
});
it("renders every top-level nav entry, not just the first", () => {
// Regression guard. The top-level nav rendered `dashboardItems[0]`
// — a hardcoded index — so any entry added after Dashboard existed
// in the array and in the build but never appeared in the sidebar.
// That's how the universal Search link shipped invisible: the
// operator asked for it, the code was correct, the entry was simply
// never rendered.
//
// Asserts the full top-level set rather than "Search exists" so the
// next person to append an entry gets a passing test instead of a
// silently invisible link.
render(<Sidebar />);
const desktop = screen.getAllByRole("complementary")[0];
for (const label of ["Dashboard", "Search"]) {
expect(
within(desktop).queryByText(label, { exact: true }),
`top-level nav should render "${label}"`,
).toBeInTheDocument();
}
// And the Search entry must actually point at the route.
const link = within(desktop).getByText("Search", { exact: true }).closest("a");
expect(link).not.toBeNull();
expect(link).toHaveAttribute("href", "/search");
});
});

View file

@ -330,12 +330,20 @@ function NavContent({ onLinkClick }: { onLinkClick?: () => void }) {
{/* Nav */}
<ScrollArea className="flex-1 px-3 py-3">
<nav className="space-y-3">
{/* Dashboard — single, top-level */}
<NavLink
item={dashboardItems[0]}
active={isActive(dashboardItems[0].href, dashboardItems, pathname)}
onClick={onLinkClick}
/>
{/* Dashboard + universal search — top-level, above the grouped nav.
Rendered as a map rather than `dashboardItems[0]`: that
hardcoded index silently dropped every entry past the
first, which is exactly how the Search link went missing
from the sidebar while existing in the array and in the
build. */}
{dashboardItems.map((item) => (
<NavLink
key={item.href}
item={item}
active={isActive(item.href, dashboardItems, pathname)}
onClick={onLinkClick}
/>
))}
<Separator className="mx-1" />