import { isValidElement } from 'react'; import { describe, expect, it } from 'vitest'; import type { RouteObject } from 'react-router-dom'; import { routes } from '@/routes'; import { Placeholder } from '@/spa/placeholder'; import { ChatPage } from '@/spa/pages/chat'; import { ProjectDetailPage } from '@/spa/pages/project-detail'; import { ProjectsPage } from '@/spa/pages/projects'; import { TasksPage } from '@/spa/pages/tasks'; function collectPaths(routeObjects: RouteObject[]): string[] { return routeObjects.flatMap((route) => [ ...(route.path ? [route.path] : []), ...(route.children ? collectPaths(route.children) : []), ]); } function findRoute(routeObjects: RouteObject[], path: string): RouteObject | undefined { for (const route of routeObjects) { if (route.path === path) return route; const nested = route.children ? findRoute(route.children, path) : undefined; if (nested) return nested; } return undefined; } describe('SPA route table', () => { it('covers every v1 parity route from the Phase P RFC', () => { expect(collectPaths(routes).sort()).toEqual( [ '/', '/admin', '/auth/provider/:provider', '/chat', '/login', '/projects', '/projects/:id', '/register', '/settings', '/tasks', ].sort(), ); }); it('separates guest and authenticated route groups', () => { const guestPaths = collectPaths(routes.at(0)?.children ?? []); const authPaths = collectPaths(routes.at(1)?.children ?? []); expect(guestPaths).toContain('/login'); expect(guestPaths).not.toContain('/chat'); expect(authPaths).toContain('/chat'); }); it.each(['/login', '/register', '/auth/provider/:provider'])( 'renders a real guest page instead of the P1 placeholder at %s', (path) => { const element = findRoute(routes, path)?.element; expect(isValidElement(element)).toBe(true); if (!isValidElement(element)) throw new Error(`Missing route element for ${path}`); expect(element.type).not.toBe(Placeholder); }, ); it('renders the real chat page instead of the P1 placeholder at /chat, inside the authenticated group', () => { const authPaths = collectPaths(routes.at(1)?.children ?? []); expect(authPaths).toContain('/chat'); const element = findRoute(routes, '/chat')?.element; expect(isValidElement(element)).toBe(true); if (!isValidElement(element)) throw new Error('Missing route element for /chat'); expect(element.type).not.toBe(Placeholder); expect(element.type).toBe(ChatPage); }); it.each([ ['/projects', ProjectsPage], ['/projects/:id', ProjectDetailPage], ['/tasks', TasksPage], ])( 'renders a real authenticated page instead of the P1 placeholder at %s', (path, expectedType) => { const element = findRoute(routes, path)?.element; expect(isValidElement(element)).toBe(true); if (!isValidElement(element)) throw new Error(`Missing route element for ${path}`); expect(element.type).not.toBe(Placeholder); expect(element.type).toBe(expectedType); }, ); it.each(['/chat', '/projects', '/projects/:id', '/tasks'])( 'defines an error boundary for %s', (path) => { const route = findRoute(routes, path); expect(route?.errorElement).toBeTruthy(); expect(isValidElement(route?.errorElement)).toBe(true); }, ); });