Skip to content

Commit b84026a

Browse files
committed
.
1 parent 89509a7 commit b84026a

File tree

9 files changed

+91
-26
lines changed

9 files changed

+91
-26
lines changed

src/app/catalog/[repoName]/[serverName]/[version]/not-found.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import Link from "next/link";
2-
import { ErrorPage } from "@/components/error-page";
2+
import { ErrorPageLayout } from "@/components/error-page";
33
import { NavigateBackButton } from "@/components/navigate-back-button";
44
import { Button } from "@/components/ui/button";
55

@@ -13,7 +13,7 @@ export default function NotFound() {
1313
className="w-fit"
1414
/>
1515

16-
<ErrorPage
16+
<ErrorPageLayout
1717
title="Server Not Found"
1818
actions={
1919
<Button asChild variant="default">
@@ -23,7 +23,7 @@ export default function NotFound() {
2323
>
2424
The MCP server you're looking for doesn't exist or has been removed from
2525
the catalog.
26-
</ErrorPage>
26+
</ErrorPageLayout>
2727
</div>
2828
);
2929
}

src/app/catalog/error.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
"use client";
22

3-
import { RuntimeError } from "@/components/error-page";
3+
import { ErrorPage } from "@/components/error-page";
44

55
interface ErrorProps {
66
error: Error & { digest?: string };
77
reset: () => void;
88
}
99

1010
export default function CatalogErrorPage({ error, reset }: ErrorProps) {
11-
return <RuntimeError error={error} reset={reset} />;
11+
return <ErrorPage error={error} reset={reset} />;
1212
}

src/app/error.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
"use client";
22

3-
import { RuntimeError } from "@/components/error-page";
3+
import { ErrorPage } from "@/components/error-page";
44

55
interface ErrorProps {
66
error: Error & { digest?: string };
77
reset: () => void;
88
}
99

1010
export default function RootErrorPage({ error, reset }: ErrorProps) {
11-
return <RuntimeError error={error} reset={reset} />;
11+
return <ErrorPage error={error} reset={reset} />;
1212
}

src/app/not-found.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import Link from "next/link";
2-
import { ErrorPage } from "@/components/error-page";
2+
import { ErrorPageLayout } from "@/components/error-page";
33
import { Navbar } from "@/components/navbar";
44
import { Button } from "@/components/ui/button";
55

@@ -8,7 +8,7 @@ export default async function NotFound() {
88
<div className="flex flex-col h-screen">
99
<Navbar />
1010
<main className="flex flex-col flex-1 overflow-hidden px-4 py-5">
11-
<ErrorPage
11+
<ErrorPageLayout
1212
title="Page Not Found"
1313
actions={
1414
<Button asChild variant="default">
@@ -17,7 +17,7 @@ export default async function NotFound() {
1717
}
1818
>
1919
The page you're looking for doesn't exist or has been moved.
20-
</ErrorPage>
20+
</ErrorPageLayout>
2121
</main>
2222
</div>
2323
);
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { render, screen } from "@testing-library/react";
2+
import userEvent from "@testing-library/user-event";
3+
import { describe, expect, it, vi } from "vitest";
4+
import { ErrorPage } from "./error-page-client";
5+
6+
describe("ErrorPage", () => {
7+
it("logs errors to console on mount", () => {
8+
const consoleError = vi
9+
.spyOn(console, "error")
10+
.mockImplementation(() => {});
11+
const error = new Error("Test error");
12+
13+
render(<ErrorPage error={error} reset={vi.fn()} />);
14+
15+
expect(consoleError).toHaveBeenCalledWith(error);
16+
consoleError.mockRestore();
17+
});
18+
19+
it("displays 'Something went wrong' title", () => {
20+
render(<ErrorPage error={new Error("Test")} reset={vi.fn()} />);
21+
22+
expect(
23+
screen.getByRole("heading", { name: /something went wrong/i }),
24+
).toBeInTheDocument();
25+
});
26+
27+
it("displays error description", () => {
28+
render(<ErrorPage error={new Error("Test")} reset={vi.fn()} />);
29+
30+
expect(
31+
screen.getByText(/an unexpected error occurred/i),
32+
).toBeInTheDocument();
33+
});
34+
35+
it("calls reset function when Try again button is clicked", async () => {
36+
const user = userEvent.setup();
37+
const reset = vi.fn();
38+
39+
render(<ErrorPage error={new Error("Test")} reset={reset} />);
40+
41+
await user.click(screen.getByRole("button", { name: /try again/i }));
42+
43+
expect(reset).toHaveBeenCalledTimes(1);
44+
});
45+
46+
it("does not expose error message to user", () => {
47+
const error = new Error("Sensitive internal error details");
48+
49+
render(<ErrorPage error={error} reset={vi.fn()} />);
50+
51+
expect(
52+
screen.queryByText(/sensitive internal error/i),
53+
).not.toBeInTheDocument();
54+
});
55+
});

src/components/error-page/runtime-error.tsx renamed to src/components/error-page/error-page-client.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@
22

33
import { useEffect } from "react";
44
import { Button } from "@/components/ui/button";
5-
import { ErrorPage } from "./error-page";
5+
import { ErrorPageLayout } from "./error-page";
66

7-
interface RuntimeErrorProps {
7+
interface ErrorPageProps {
88
error: Error & { digest?: string };
99
reset: () => void;
1010
}
1111

12-
export function RuntimeError({ error, reset }: RuntimeErrorProps) {
12+
export function ErrorPage({ error, reset }: ErrorPageProps) {
1313
useEffect(() => {
1414
console.error(error);
1515
}, [error]);
1616

1717
return (
18-
<ErrorPage
18+
<ErrorPageLayout
1919
title="Something went wrong"
2020
actions={
2121
<Button onClick={reset} variant="default">
@@ -24,6 +24,6 @@ export function RuntimeError({ error, reset }: RuntimeErrorProps) {
2424
}
2525
>
2626
An unexpected error occurred. Please try again.
27-
</ErrorPage>
27+
</ErrorPageLayout>
2828
);
2929
}

src/components/error-page/error-page.test.tsx

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,36 @@
11
import { render, screen } from "@testing-library/react";
22
import { describe, expect, it } from "vitest";
3-
import { ErrorPage } from "./error-page";
3+
import { ErrorPageLayout } from "./error-page";
44

5-
describe("ErrorPage", () => {
5+
describe("ErrorPageLayout", () => {
66
it("displays the title", () => {
7-
render(<ErrorPage title="Test Error">Error description</ErrorPage>);
7+
render(
8+
<ErrorPageLayout title="Test Error">Error description</ErrorPageLayout>,
9+
);
810

911
expect(
1012
screen.getByRole("heading", { name: /test error/i }),
1113
).toBeInTheDocument();
1214
});
1315

1416
it("displays children as description", () => {
15-
render(<ErrorPage title="Error">This is the error message</ErrorPage>);
17+
render(
18+
<ErrorPageLayout title="Error">
19+
This is the error message
20+
</ErrorPageLayout>,
21+
);
1622

1723
expect(screen.getByText(/this is the error message/i)).toBeInTheDocument();
1824
});
1925

2026
it("displays action buttons when provided", () => {
2127
render(
22-
<ErrorPage
28+
<ErrorPageLayout
2329
title="Error"
2430
actions={<button type="button">Click me</button>}
2531
>
2632
Description
27-
</ErrorPage>,
33+
</ErrorPageLayout>,
2834
);
2935

3036
expect(
@@ -34,7 +40,7 @@ describe("ErrorPage", () => {
3440

3541
it("displays a decorative illustration", () => {
3642
const { container } = render(
37-
<ErrorPage title="Error">Description</ErrorPage>,
43+
<ErrorPageLayout title="Error">Description</ErrorPageLayout>,
3844
);
3945

4046
const svg = container.querySelector("svg[aria-hidden='true']");

src/components/error-page/error-page.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
import type { ReactNode } from "react";
22
import { IllustrationError } from "@/components/illustrations/illustration-error";
33

4-
interface ErrorPageProps {
4+
interface ErrorPageLayoutProps {
55
title: string;
66
children: ReactNode;
77
actions?: ReactNode;
88
}
99

10-
export function ErrorPage({ title, children, actions }: ErrorPageProps) {
10+
export function ErrorPageLayout({
11+
title,
12+
children,
13+
actions,
14+
}: ErrorPageLayoutProps) {
1115
return (
1216
<div className="flex items-center justify-center min-h-[80vh]">
1317
<div className="flex flex-col items-center text-center gap-4 max-w-md">

src/components/error-page/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
export { ErrorPage } from "./error-page";
2-
export { RuntimeError } from "./runtime-error";
1+
export { ErrorPageLayout } from "./error-page";
2+
export { ErrorPage } from "./error-page-client";

0 commit comments

Comments
 (0)