diff --git a/apps/loopover-ui/src/routes/roadmap.test.tsx b/apps/loopover-ui/src/routes/roadmap.test.tsx new file mode 100644 index 0000000000..eb32492653 --- /dev/null +++ b/apps/loopover-ui/src/routes/roadmap.test.tsx @@ -0,0 +1,41 @@ +import { render, screen } from "@testing-library/react"; +import { describe, expect, it, vi } from "vitest"; +import type { ReactNode } from "react"; + +// jsdom has no IntersectionObserver; RoadmapPage wraps its content in , a framer-motion +// viewport-triggered animation that needs one to mount. No other test in this file tree renders +// Reveal yet, so there's no existing global stub to reuse -- a minimal no-op observer is enough, +// since the tests here only assert on rendered link hrefs, not the reveal animation itself. +class MockIntersectionObserver { + observe() {} + unobserve() {} + disconnect() {} +} +vi.stubGlobal("IntersectionObserver", MockIntersectionObserver); + +// Stub TanStack Router the same way install.permissions.test.tsx does: Link becomes a plain +// carrying the resolved `to` as its href, so the rendered destination can be asserted directly. +vi.mock("@tanstack/react-router", () => ({ + createFileRoute: () => () => ({}), + Link: ({ to, children }: { to: string; children: ReactNode }) => {children}, +})); + +import { RoadmapPage } from "./roadmap"; + +// #8669: the "Phase 3: repo owner intake console" card linked to /app/repos, which defaults to the +// Maintainer console tab (app.repos.tsx:27) with no search param -- the opposite surface from what +// the card describes. Locks in the fix to the dedicated /app/owner route, and guards that no other +// phase's link moved as a side effect. +describe("RoadmapPage phase links (#8669)", () => { + it("routes the repo owner intake console card to the dedicated Owner workspace, not the Maintainer tab", () => { + render(); + const link = screen.getByRole("link", { name: /Open repos console/i }); + expect(link.getAttribute("href")).toBe("/app/owner"); + }); + + it("leaves the maintainer trust card's link unchanged (sibling regression guard)", () => { + render(); + const link = screen.getByRole("link", { name: /Open maintainer console/i }); + expect(link.getAttribute("href")).toBe("/app/maintainer"); + }); +}); diff --git a/apps/loopover-ui/src/routes/roadmap.tsx b/apps/loopover-ui/src/routes/roadmap.tsx index 1b1accfd08..3527116240 100644 --- a/apps/loopover-ui/src/routes/roadmap.tsx +++ b/apps/loopover-ui/src/routes/roadmap.tsx @@ -100,7 +100,7 @@ const LINK_MAP: Record = { to: "/app/maintainer", label: "Open maintainer console", }, - "Phase 3: repo owner intake console": { to: "/app/repos", label: "Open repos console" }, + "Phase 3: repo owner intake console": { to: "/app/owner", label: "Open repos console" }, "Phase 4: adoption analytics and launch system": { to: "/app/analytics", label: "Open analytics", @@ -108,7 +108,7 @@ const LINK_MAP: Record = { "Phase 5: ecosystem distribution": { to: "/app/digest", label: "Preview the digest" }, }; -function RoadmapPage() { +export function RoadmapPage() { const grouped = COLUMNS.map((c) => ({ ...c, items: ROADMAP_ITEMS.filter((r) => r.status === c.key),