Co-Authored-By: Claude Haiku 4.5 <[email protected]>
87 lines
2.4 KiB
TypeScript
87 lines
2.4 KiB
TypeScript
import { act } from 'react';
|
|
import { createRoot, type Root } from 'react-dom/client';
|
|
import { createMemoryRouter, RouterProvider, type RouteObject } from 'react-router-dom';
|
|
import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from 'vitest';
|
|
|
|
const { useSessionMock } = vi.hoisted(() => ({
|
|
useSessionMock: vi.fn(),
|
|
}));
|
|
|
|
vi.mock('@/lib/auth-client', () => ({
|
|
useSession: useSessionMock,
|
|
}));
|
|
|
|
import { routes } from '@/routes';
|
|
|
|
function Boom(): never {
|
|
throw new Error('resource route render blew up');
|
|
}
|
|
|
|
function replaceRouteElementWithBoom(nodes: RouteObject[], path: string): RouteObject[] {
|
|
return nodes.map((node) => {
|
|
const cloned: RouteObject = { ...node };
|
|
if (cloned.path === path) {
|
|
cloned.element = <Boom />;
|
|
}
|
|
if (cloned.children) {
|
|
cloned.children = replaceRouteElementWithBoom(cloned.children, path);
|
|
}
|
|
return cloned;
|
|
});
|
|
}
|
|
|
|
let root: Root | null = null;
|
|
let container: HTMLDivElement;
|
|
|
|
beforeAll(() => {
|
|
Object.defineProperty(globalThis, 'IS_REACT_ACT_ENVIRONMENT', {
|
|
configurable: true,
|
|
value: true,
|
|
});
|
|
});
|
|
|
|
afterAll(() => {
|
|
Reflect.deleteProperty(globalThis, 'IS_REACT_ACT_ENVIRONMENT');
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await act(async () => {
|
|
root?.unmount();
|
|
});
|
|
document.body.replaceChildren();
|
|
root = null;
|
|
useSessionMock.mockReset();
|
|
});
|
|
|
|
describe('resource route error boundaries', () => {
|
|
it.each(['/projects', '/projects/:id', '/tasks'])(
|
|
'renders a recoverable fallback when %s throws during route render',
|
|
async (path) => {
|
|
useSessionMock.mockReturnValue({ data: { user: { id: 'user-1' } }, isPending: false });
|
|
|
|
const initialEntry = path === '/projects/:id' ? '/projects/project-1' : path;
|
|
const router = createMemoryRouter(replaceRouteElementWithBoom(routes, path), {
|
|
initialEntries: [initialEntry],
|
|
});
|
|
|
|
container = document.createElement('div');
|
|
document.body.append(container);
|
|
root = createRoot(container);
|
|
|
|
const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
try {
|
|
await act(async () => {
|
|
root?.render(<RouterProvider router={router} />);
|
|
});
|
|
|
|
expect(consoleErrorSpy).toHaveBeenCalled();
|
|
} finally {
|
|
consoleErrorSpy.mockRestore();
|
|
}
|
|
|
|
expect(container.textContent).not.toBe('');
|
|
expect(container.querySelector('[role="alert"]')).toBeTruthy();
|
|
},
|
|
);
|
|
});
|