2026-06-28 15:02:07 +02:00
|
|
|
import { render, screen } from '@testing-library/react'
|
|
|
|
|
import { http, HttpResponse } from 'msw'
|
|
|
|
|
import { createMemoryRouter, RouterProvider } from 'react-router'
|
|
|
|
|
import { describe, expect, it } from 'vitest'
|
|
|
|
|
import { AuthProvider } from './auth/AuthProvider'
|
|
|
|
|
import { routes } from './router'
|
|
|
|
|
import { server } from './test/server'
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Smoke tests for the REAL route-object array (`routes` from ./router), driven
|
|
|
|
|
* through `createMemoryRouter`. Unlike the guard/page component tests, these
|
|
|
|
|
* exercise the actual shipped config end-to-end — catch-all redirect, both
|
|
|
|
|
* guards, and the real pages — so a future swapped path/element regression in
|
|
|
|
|
* router.tsx is caught here instead of only in hand-built test route trees.
|
|
|
|
|
*/
|
|
|
|
|
describe('app router config', () => {
|
|
|
|
|
it('unknown paths redirect to the app root', async () => {
|
|
|
|
|
server.use(
|
|
|
|
|
http.get('http://localhost/api/me', () =>
|
|
|
|
|
HttpResponse.json({ id: 'u1', email: 'a@b.com' }),
|
|
|
|
|
),
|
2026-07-05 10:39:37 +02:00
|
|
|
http.get('http://localhost/api/scenarios', () =>
|
|
|
|
|
HttpResponse.json({
|
|
|
|
|
'@context': '/api/contexts/Scenario',
|
|
|
|
|
'@id': '/api/scenarios',
|
|
|
|
|
'@type': 'hydra:Collection',
|
|
|
|
|
member: [
|
|
|
|
|
{
|
|
|
|
|
'@id': '/api/scenarios/11111111-1111-1111-1111-111111111111',
|
|
|
|
|
'@type': 'Scenario',
|
|
|
|
|
name: 'Emergency Fund',
|
|
|
|
|
description: 'Rainy day savings',
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
totalItems: 1,
|
|
|
|
|
}),
|
|
|
|
|
),
|
2026-06-28 15:02:07 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const router = createMemoryRouter(routes, {
|
|
|
|
|
initialEntries: ['/some/unknown/path'],
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
render(
|
|
|
|
|
<AuthProvider>
|
|
|
|
|
<RouterProvider router={router} />
|
|
|
|
|
</AuthProvider>,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
expect(await screen.findByText('Emergency Fund')).toBeInTheDocument()
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
it('the /login route resolves to the login page for a guest', async () => {
|
|
|
|
|
server.use(
|
|
|
|
|
http.get('http://localhost/api/me', () =>
|
|
|
|
|
HttpResponse.json({ message: 'unauthorized' }, { status: 401 }),
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const router = createMemoryRouter(routes, { initialEntries: ['/login'] })
|
|
|
|
|
|
|
|
|
|
render(
|
|
|
|
|
<AuthProvider>
|
|
|
|
|
<RouterProvider router={router} />
|
|
|
|
|
</AuthProvider>,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
expect(await screen.findByLabelText(/email/i)).toBeInTheDocument()
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
it('an authenticated user at /login is redirected to the app', async () => {
|
|
|
|
|
server.use(
|
|
|
|
|
http.get('http://localhost/api/me', () =>
|
|
|
|
|
HttpResponse.json({ id: 'u1', email: 'a@b.com' }),
|
|
|
|
|
),
|
2026-07-05 10:39:37 +02:00
|
|
|
http.get('http://localhost/api/scenarios', () =>
|
|
|
|
|
HttpResponse.json({
|
|
|
|
|
'@context': '/api/contexts/Scenario',
|
|
|
|
|
'@id': '/api/scenarios',
|
|
|
|
|
'@type': 'hydra:Collection',
|
|
|
|
|
member: [
|
|
|
|
|
{
|
|
|
|
|
'@id': '/api/scenarios/11111111-1111-1111-1111-111111111111',
|
|
|
|
|
'@type': 'Scenario',
|
|
|
|
|
name: 'Emergency Fund',
|
|
|
|
|
description: 'Rainy day savings',
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
totalItems: 1,
|
|
|
|
|
}),
|
|
|
|
|
),
|
2026-06-28 15:02:07 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const router = createMemoryRouter(routes, { initialEntries: ['/login'] })
|
|
|
|
|
|
|
|
|
|
render(
|
|
|
|
|
<AuthProvider>
|
|
|
|
|
<RouterProvider router={router} />
|
|
|
|
|
</AuthProvider>,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
expect(await screen.findByText('Emergency Fund')).toBeInTheDocument()
|
|
|
|
|
expect(screen.queryByLabelText(/email/i)).not.toBeInTheDocument()
|
|
|
|
|
})
|
|
|
|
|
})
|