src/router.test.tsx
Rama main · réplica de lectura del repositorio original.
import { cleanup, render, screen, waitFor } from '@testing-library/react'
import type { ReactNode } from 'react'
import { afterEach, describe, expect, it, vi } from 'vitest'
import { AppRouter, queryClient } from '@/router'
vi.mock('@/features/account/account-center', () => ({
AccountCenterLayout: ({ children }: { children: ReactNode }) => children,
AccountAgentsPage: () => <h1>Agents route</h1>,
AccountApplicationsPage: () => <h1>Applications route</h1>,
AccountConnectionsPage: () => <h1>Connections route</h1>,
AccountDataPrivacyPage: () => <h1>Data & privacy route</h1>,
AccountOrganizationDetailPage: () => <h1>Organization route</h1>,
AccountOrganizationsPage: () => <h1>Organizations route</h1>,
AccountOverviewPage: () => <h1>Account overview route</h1>,
AccountProfilePage: () => <h1>Profile route</h1>,
AccountSecurityPage: () => <h1>Profile route</h1>,
}))
vi.mock('@/features/agents/agent-identity-approval', () => ({
AgentIdentityApproval: () => <h1>Agent enrollment route</h1>,
}))
vi.mock('@/features/auth/onboarding-page', () => ({
OnboardingRoute: () => <h1>First-admin onboarding</h1>,
}))
vi.mock('@/features/auth/pages/recovery', () => ({
AuthCallbackPage: () => <h1>Auth callback route</h1>,
EmailVerificationPage: () => <h1>Email verification route</h1>,
ForgotPasswordPage: () => <h1>Forgot password route</h1>,
}))
vi.mock('@/features/auth/pages/sign-in', () => ({
SignInPage: () => <h1>Sign in route</h1>,
}))
vi.mock('@/features/auth/pages/sign-up', () => ({
SignUpPage: () => <h1>Sign up route</h1>,
}))
vi.mock('@/features/auth/device-authorization', () => ({
DeviceVerification: () => <h1>Device approval route</h1>,
}))
afterEach(() => {
cleanup()
queryClient.clear()
vi.restoreAllMocks()
window.history.pushState(null, '', '/')
})
describe('root route', () => {
it('renders the Account Center overview at the root', async () => {
const fetchSpy = vi.spyOn(window, 'fetch').mockImplementation(accountRouteResponse)
render(<AppRouter />)
expect(await screen.findByRole('heading', { name: 'Account overview route' })).toBeTruthy()
expect(window.location.pathname).toBe('/')
expect(fetchSpy).toHaveBeenCalledWith('/api/account/profile', {
body: undefined,
headers: expect.any(Headers),
method: 'GET',
})
})
it('authenticates profile routes before rendering them', async () => {
const fetchSpy = vi.spyOn(window, 'fetch').mockImplementation(accountRouteResponse)
window.history.pushState(null, '', '/profile')
render(<AppRouter />)
expect(await screen.findByRole('heading', { name: 'Profile route' })).toBeTruthy()
expect(window.location.pathname).toBe('/profile')
expect(fetchSpy).toHaveBeenCalledWith('/api/account/profile', {
body: undefined,
headers: expect.any(Headers),
method: 'GET',
})
})
it('authenticates Data & privacy before rendering it', async () => {
const fetchSpy = vi.spyOn(window, 'fetch').mockImplementation(accountRouteResponse)
window.history.pushState(null, '', '/data-privacy')
render(<AppRouter />)
expect(await screen.findByRole('heading', { name: 'Data & privacy route' })).toBeTruthy()
expect(window.location.pathname).toBe('/data-privacy')
expect(fetchSpy).toHaveBeenCalledWith('/api/account/profile', {
body: undefined,
headers: expect.any(Headers),
method: 'GET',
})
})
it('routes completed account connections to their Account Center page [spec: account-center/account-section-routes]', async () => {
const fetchSpy = vi.spyOn(window, 'fetch').mockImplementation(accountRouteResponse)
window.history.pushState(null, '', '/connections?resource_connection=connected')
render(<AppRouter />)
expect(await screen.findByRole('heading', { name: 'Connections route' })).toBeTruthy()
expect(window.location.pathname).toBe('/connections')
expect(fetchSpy).toHaveBeenCalledWith('/api/account/profile', {
body: undefined,
headers: expect.any(Headers),
method: 'GET',
})
})
it('authenticates Agent enrollment before rendering it', async () => {
const fetchSpy = vi.spyOn(window, 'fetch').mockImplementation(accountRouteResponse)
window.history.pushState(null, '', '/agent/enrollment?agent_id=agent-1&code=ABCD-1234')
render(<AppRouter />)
expect(await screen.findByRole('heading', { name: 'Agent enrollment route' })).toBeTruthy()
expect(fetchSpy).toHaveBeenCalledWith('/api/account/profile', {
body: undefined,
headers: expect.any(Headers),
method: 'GET',
})
})
it('authenticates device approval before rendering it', async () => {
const fetchSpy = vi
.spyOn(window, 'fetch')
.mockImplementation((input) =>
String(input) === '/api/configz' ? Promise.resolve(jsonResponse(configz)) : accountRouteResponse(input),
)
window.history.pushState(null, '', '/auth/device?user_code=ABCD-1234')
render(<AppRouter />)
expect(await screen.findByRole('heading', { name: 'Device approval route' })).toBeTruthy()
expect(fetchSpy).toHaveBeenCalledWith('/api/account/profile', {
body: undefined,
headers: expect.any(Headers),
method: 'GET',
})
})
it('authenticates the device code entry route', async () => {
const fetchSpy = vi
.spyOn(window, 'fetch')
.mockImplementation((input) =>
String(input) === '/api/configz' ? Promise.resolve(jsonResponse(configz)) : accountRouteResponse(input),
)
window.history.pushState(null, '', '/auth/device')
render(<AppRouter />)
expect(await screen.findByRole('heading', { name: 'Device approval route' })).toBeTruthy()
expect(fetchSpy).toHaveBeenCalledWith('/api/account/profile', {
body: undefined,
headers: expect.any(Headers),
method: 'GET',
})
})
it('preserves device approval return path when signed out', async () => {
vi.spyOn(window, 'fetch').mockImplementation(() => Promise.resolve(jsonResponse({ error: 'unauthorized' }, 401)))
window.history.pushState(null, '', '/auth/device?user_code=ABCD-1234')
render(<AppRouter />)
await waitFor(() => expect(window.location.pathname).toBe('/auth/sign-in'))
expect(window.location.search).toBe('?return_to=%2Fauth%2Fdevice%3Fuser_code%3DABCD-1234')
})
it('serves hosted auth from /auth routes only', async () => {
window.history.pushState(null, '', '/auth/sign-in')
render(<AppRouter />)
expect(await screen.findByRole('heading', { name: 'Sign in route' })).toBeTruthy()
cleanup()
window.history.pushState(null, '', '/sign-in')
render(<AppRouter />)
await waitFor(() => expect(screen.queryByRole('heading', { name: 'Sign in route' })).toBeNull())
expect(await screen.findByRole('heading', { name: 'Page not found.' })).toBeTruthy()
})
})
const user = {
id: 'user-1',
email: 'jane@example.com',
name: 'Jane Stone',
displayName: 'Jane Stone',
username: 'jane',
role: 'user',
}
function accountRouteResponse(input: RequestInfo | URL) {
if (String(input) === '/api/account/security') {
return Promise.resolve(
jsonResponse({
security: {
mfa: { enabled: false, factors: [] },
passkeys: { enabled: true, count: 0 },
policy: { mfa: { mode: 'optional' } },
},
}),
)
}
return Promise.resolve(
jsonResponse({
activeOrganizationId: null,
user,
access: {
canCreateOrganization: false,
showOrganizations: false,
platformOperator: false,
consoleOrganizations: [],
},
}),
)
}
const configz = {
onboarding: { required: false, href: '/onboarding' },
signIn: {
passwordEnabled: true,
signupEnabled: true,
socialLoginEnabled: false,
emailOtpEnabled: false,
usernameEnabled: false,
identifierFirst: false,
},
builtInProviders: {
email: { enabled: true },
phone: { enabled: false },
web3Wallet: { enabled: false, chains: [1], allowSignUp: false },
passkey: { allowSignUp: false },
oneTap: { enabled: false },
},
branding: {
logoUrl: null,
faviconUrl: null,
primaryColor: '#007b83',
backgroundColor: '#ffffff',
customCss: null,
},
identityProviders: [],
links: { termsUri: null, privacyUri: null, supportEmail: null },
copy: { productName: 'Realmroot' },
}
function jsonResponse(body: unknown, status = 200) {
return new Response(JSON.stringify(body), {
status,
headers: { 'Content-Type': 'application/json' },
})
}