diff --git a/packages/web/src/app/projects/[projectId]/page.test.tsx b/packages/web/src/app/projects/[projectId]/page.test.tsx index bb1ab40f6..3b378fc1b 100644 --- a/packages/web/src/app/projects/[projectId]/page.test.tsx +++ b/packages/web/src/app/projects/[projectId]/page.test.tsx @@ -53,5 +53,7 @@ describe("ProjectPage", () => { expect(screen.getByText("This project's config failed to load")).toBeInTheDocument(); expect(screen.getByText("Local config failed validation")).toBeInTheDocument(); expect(screen.queryByTestId("dashboard")).not.toBeInTheDocument(); + expect(screen.getByRole("link", { name: "Back to dashboard" })).toHaveAttribute("href", "/"); + expect(screen.queryByRole("link", { name: "Edit settings" })).not.toBeInTheDocument(); }); }); diff --git a/packages/web/src/app/projects/[projectId]/settings/page.test.tsx b/packages/web/src/app/projects/[projectId]/settings/page.test.tsx index 23686b24c..ae26393c6 100644 --- a/packages/web/src/app/projects/[projectId]/settings/page.test.tsx +++ b/packages/web/src/app/projects/[projectId]/settings/page.test.tsx @@ -77,5 +77,7 @@ describe("ProjectSettingsPage", () => { ).toBeInTheDocument(); expect(screen.getByText("Local config failed validation")).toBeInTheDocument(); expect(screen.queryByRole("button", { name: "Save changes" })).not.toBeInTheDocument(); + expect(screen.getByRole("link", { name: "Back to dashboard" })).toHaveAttribute("href", "/"); + expect(screen.queryByRole("link", { name: "Edit settings" })).not.toBeInTheDocument(); }); }); diff --git a/packages/web/src/components/DegradedProjectState.tsx b/packages/web/src/components/DegradedProjectState.tsx index 399165893..c02c734a5 100644 --- a/packages/web/src/components/DegradedProjectState.tsx +++ b/packages/web/src/components/DegradedProjectState.tsx @@ -66,12 +66,6 @@ export function DegradedProjectState({ > Back to dashboard - - Edit settings - diff --git a/packages/web/src/components/__tests__/DegradedProjectState.test.tsx b/packages/web/src/components/__tests__/DegradedProjectState.test.tsx new file mode 100644 index 000000000..561af112f --- /dev/null +++ b/packages/web/src/components/__tests__/DegradedProjectState.test.tsx @@ -0,0 +1,86 @@ +import { render, screen } from "@testing-library/react"; +import { describe, expect, it, vi } from "vitest"; +import { DegradedProjectState } from "@/components/DegradedProjectState"; + +vi.mock("next/link", () => ({ + default: ({ + children, + ...props + }: React.PropsWithChildren>) => ( + {children} + ), +})); + +vi.mock("@/components/RepairDegradedProjectButton", () => ({ + RepairDegradedProjectButton: ({ projectId }: { projectId: string }) => ( + + ), +})); + +const baseProps = { + projectId: "my-project", + resolveError: "Local config at /tmp/my-project/agent-orchestrator.yaml failed validation: bad field", + projectPath: "/tmp/my-project", +}; + +describe("DegradedProjectState", () => { + it("renders the default heading", () => { + render(); + expect(screen.getByText("This project's config failed to load")).toBeInTheDocument(); + }); + + it("renders a custom heading when provided", () => { + render(); + expect(screen.getByText("Custom heading")).toBeInTheDocument(); + }); + + it("displays the resolve error", () => { + render(); + expect(screen.getByText(baseProps.resolveError)).toBeInTheDocument(); + }); + + it("extracts and displays the config path from the resolve error", () => { + render(); + expect( + screen.getByText("/tmp/my-project/agent-orchestrator.yaml"), + ).toBeInTheDocument(); + }); + + it("falls back to the project path when the config path cannot be parsed from the error", () => { + render( + , + ); + expect( + screen.getByText("/tmp/my-project/agent-orchestrator.yaml or .yml"), + ).toBeInTheDocument(); + }); + + it("renders 'Back to dashboard' link pointing to /", () => { + render(); + const link = screen.getByRole("link", { name: "Back to dashboard" }); + expect(link).toHaveAttribute("href", "/"); + }); + + it("does not render an 'Edit settings' link", () => { + render(); + expect(screen.queryByRole("link", { name: "Edit settings" })).not.toBeInTheDocument(); + }); + + it("does not show the repair button for a generic validation error", () => { + render(); + expect(screen.queryByRole("button", { name: /repair/i })).not.toBeInTheDocument(); + }); + + it("shows the repair button when the error indicates a wrapped projects format", () => { + render( + , + ); + expect(screen.getByRole("button", { name: /repair/i })).toBeInTheDocument(); + }); +});