Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 124 additions & 0 deletions app/error.empty-fallback.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// app/error.empty-fallback.test.tsx

import { describe, expect, it, vi, beforeEach } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom/vitest';

vi.mock('next/link', () => ({
default: ({
children,
...props
}: React.AnchorHTMLAttributes<HTMLAnchorElement> & { children: React.ReactNode }) => (
<a {...props}>{children}</a>
),
}));

vi.mock('sonner', () => ({
toast: {
success: vi.fn(),
error: vi.fn(),
},
}));

import ErrorBoundary from './error';

describe('Root Error Boundary - Empty & Missing Input Fallbacks', () => {
beforeEach(() => {
vi.clearAllMocks();
// Mock clipboard API
Object.defineProperty(navigator, 'clipboard', {
value: {
writeText: vi.fn().mockResolvedValue(undefined),
},
configurable: true,
writable: true,
});
});

it('renders successfully when error is null', () => {
expect(() =>
render(<ErrorBoundary error={null as unknown as Error} reset={vi.fn()} />)
).not.toThrow();

expect(
screen.getByRole('heading', {
name: /Looks like an exception was thrown in the application/i,
})
).toBeInTheDocument();
expect(screen.getByText('Unknown runtime error occurred.')).toBeInTheDocument();
});

it('renders successfully when error is undefined', () => {
expect(() =>
render(<ErrorBoundary error={undefined as unknown as Error} reset={vi.fn()} />)
).not.toThrow();

expect(
screen.getByRole('heading', {
name: /Looks like an exception was thrown in the application/i,
})
).toBeInTheDocument();
expect(screen.getByText('Unknown runtime error occurred.')).toBeInTheDocument();
});

it('renders successfully when error is an empty object', () => {
expect(() =>
render(<ErrorBoundary error={{} as unknown as Error} reset={vi.fn()} />)
).not.toThrow();

expect(
screen.getByRole('heading', {
name: /Looks like an exception was thrown in the application/i,
})
).toBeInTheDocument();
expect(screen.getByText('Unknown runtime error occurred.')).toBeInTheDocument();
});

it('renders successfully when error has no message property', () => {
expect(() =>
render(<ErrorBoundary error={{ name: 'CustomError' } as unknown as Error} reset={vi.fn()} />)
).not.toThrow();

expect(
screen.getByRole('heading', {
name: /Looks like an exception was thrown in the application/i,
})
).toBeInTheDocument();
expect(screen.getByText('Unknown runtime error occurred.')).toBeInTheDocument();
});

it('renders successfully when error message is an empty string', () => {
expect(() => render(<ErrorBoundary error={new Error('')} reset={vi.fn()} />)).not.toThrow();

expect(
screen.getByRole('heading', {
name: /Looks like an exception was thrown in the application/i,
})
).toBeInTheDocument();
expect(screen.getByText('Unknown runtime error occurred.')).toBeInTheDocument();
});

it('renders interactive elements and triggers actions correctly in fallback state', async () => {
const resetMock = vi.fn();
render(<ErrorBoundary error={{} as unknown as Error} reset={resetMock} />);

// Check actions
const retryButton = screen.getByRole('button', { name: /git fetch/i });
expect(retryButton).toBeInTheDocument();
fireEvent.click(retryButton);
expect(resetMock).toHaveBeenCalledOnce();

const homeLink = screen.getByRole('link', { name: /Return to main/i });
expect(homeLink).toBeInTheDocument();

// Check clipboard copy fallback behavior
const terminalContainer = screen.getByText('commitpulse — error').closest('div');
expect(terminalContainer).toBeInTheDocument();
if (terminalContainer) {
fireEvent.click(terminalContainer);
expect(navigator.clipboard.writeText).toHaveBeenCalledWith(
expect.stringContaining('Unknown exception in the render tree.')
);
}
});
});
10 changes: 7 additions & 3 deletions app/error.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,20 @@ export default function ErrorBoundary({
reset: () => void;
}) {
useEffect(() => {
console.error(error);
if (error) {
console.error(error);
}
}, [error]);

const errorMessage = error?.message || '';

const terminalContent = `git status

fatal: Your branch and 'origin/main' have diverged,
and have 1 and 1 different commits each, respectively.

Error details:
${error.message || 'Unknown exception in the render tree.'}`;
${errorMessage || 'Unknown exception in the render tree.'}`;

const handleCopy = async () => {
try {
Expand Down Expand Up @@ -88,7 +92,7 @@ export default function ErrorBoundary({
fatal: Your branch and &apos;origin/main&apos; have diverged.
<br />
<span className="text-white/60 text-xs mt-2 block">
{error.message || 'Unknown runtime error occurred.'}
{errorMessage || 'Unknown runtime error occurred.'}
</span>
</p>

Expand Down
72 changes: 72 additions & 0 deletions app/global-error.empty-fallback.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// app/global-error.empty-fallback.test.tsx

import { describe, expect, it, vi } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom/vitest';

vi.mock('next/link', () => ({
default: ({
children,
...props
}: React.AnchorHTMLAttributes<HTMLAnchorElement> & { children: React.ReactNode }) => (
<a {...props}>{children}</a>
),
}));

import GlobalError from './global-error';

describe('Global Error Page - Empty & Missing Input Fallbacks', () => {
it('renders successfully when error is null', () => {
expect(() =>
render(<GlobalError error={null as unknown as Error} reset={vi.fn()} />)
).not.toThrow();

expect(screen.getByText('500')).toBeInTheDocument();
expect(screen.getByText('A critical error occurred at the root level.')).toBeInTheDocument();
expect(screen.getByText('Unknown global error')).toBeInTheDocument();
});

it('renders successfully when error is undefined', () => {
expect(() =>
render(<GlobalError error={undefined as unknown as Error} reset={vi.fn()} />)
).not.toThrow();

expect(screen.getByText('500')).toBeInTheDocument();
expect(screen.getByText('Unknown global error')).toBeInTheDocument();
});

it('renders successfully when error is an empty object', () => {
expect(() =>
render(<GlobalError error={{} as unknown as Error} reset={vi.fn()} />)
).not.toThrow();

expect(screen.getByText('500')).toBeInTheDocument();
expect(screen.getByText('Unknown global error')).toBeInTheDocument();
});

it('renders successfully when error has no message property', () => {
expect(() =>
render(<GlobalError error={{ name: 'CustomError' } as unknown as Error} reset={vi.fn()} />)
).not.toThrow();

expect(screen.getByText('500')).toBeInTheDocument();
expect(screen.getByText('Unknown global error')).toBeInTheDocument();
});

it('renders successfully when error message is an empty string', () => {
expect(() => render(<GlobalError error={new Error('')} reset={vi.fn()} />)).not.toThrow();

expect(screen.getByText('500')).toBeInTheDocument();
expect(screen.getByText('Unknown global error')).toBeInTheDocument();
});

it('renders interactive elements and triggers reset correctly in fallback state', () => {
const resetMock = vi.fn();
render(<GlobalError error={{} as unknown as Error} reset={resetMock} />);

const retryButton = screen.getByRole('button', { name: /Try again/i });
expect(retryButton).toBeInTheDocument();
fireEvent.click(retryButton);
expect(resetMock).toHaveBeenCalledOnce();
});
});
5 changes: 3 additions & 2 deletions app/global-error.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
'use client';
import Link from 'next/link';

export default function GlobalError({
error,
Expand All @@ -8,6 +7,8 @@ export default function GlobalError({
error: Error & { digest?: string };
reset: () => void;
}) {
const errorMessage = error?.message || '';

return (
<html lang="en">
<body className="bg-black text-white antialiased">
Expand All @@ -17,7 +18,7 @@ export default function GlobalError({
<p className="text-xl text-white/80">A critical error occurred at the root level.</p>
<div className="p-4 bg-white/5 rounded-xl border border-white/10 text-left w-full overflow-auto">
<code className="text-sm text-red-400 font-mono">
{error.message || 'Unknown global error'}
{errorMessage || 'Unknown global error'}
</code>
</div>
<button
Expand Down
Loading