Changes back-end unavailable to redirect to login instead of setup page

This commit is contained in:
2026-06-23 22:13:01 +02:00
parent 2544e20b3c
commit b84e2f8e3e
4 changed files with 33 additions and 7 deletions
+1 -1
View File
@@ -9,7 +9,7 @@ export const handlers = [...authHandlers, ...userHandlers, ...setupHandlers, ...
export { authHandlers } from './auth/handlers'; export { authHandlers } from './auth/handlers';
export { userHandlers } from './users/handlers'; export { userHandlers } from './users/handlers';
export { setupHandlers, setupUninitializedHandlers, setupConflictHandlers } from './setup/handlers'; export { setupHandlers, setupUninitializedHandlers, setupConflictHandlers, setupNetworkErrorHandlers } from './setup/handlers';
export { invitationHandlers } from './invitation/handlers'; export { invitationHandlers } from './invitation/handlers';
export { availabilityHandlers } from './availability/handlers'; export { availabilityHandlers } from './availability/handlers';
export * from './auth/fixtures'; export * from './auth/fixtures';
+5
View File
@@ -37,6 +37,11 @@ export const setupHandlers = [
}), }),
]; ];
/** Override: simulates network error on setup status — backend unreachable. */
export const setupNetworkErrorHandlers = [
http.get(`${API_BASE}/api/v1/Setup/status`, () => HttpResponse.error()),
];
/** Override: returns not-initialized status — use in tests for InitGuard. */ /** Override: returns not-initialized status — use in tests for InitGuard. */
export const setupUninitializedHandlers = [ export const setupUninitializedHandlers = [
http.get(`${API_BASE}/api/v1/Setup/status`, () => http.get(`${API_BASE}/api/v1/Setup/status`, () =>
+8 -5
View File
@@ -8,7 +8,7 @@ import {
} from '@tanstack/react-router'; } from '@tanstack/react-router';
import type { AuthContextValue } from '@/contexts/auth-context'; import type { AuthContextValue } from '@/contexts/auth-context';
import type { SetupStatus } from '@/api/types'; import type { SetupStatus } from '@/api/types';
import { api } from '@/lib/api-client'; import { api, NetworkError } from '@/lib/api-client';
import { AppLayout } from '@/components/layout/AppLayout'; import { AppLayout } from '@/components/layout/AppLayout';
import { LoginPage } from '@/pages/LoginPage'; import { LoginPage } from '@/pages/LoginPage';
import { NotFoundPage } from '@/pages/NotFoundPage'; import { NotFoundPage } from '@/pages/NotFoundPage';
@@ -99,10 +99,13 @@ const rootRoute = createRootRouteWithContext<RouterContext>()({
try { try {
status = await fetchSetupStatus(); status = await fetchSetupStatus();
} catch (err) { } catch (err) {
// On network failure, assume not initialized so the user can set up if (err instanceof NetworkError) {
// the system once the backend is reachable. Logging helps debugging. // Backend unreachable: skip setup redirect and show the login page instead.
console.warn('[InitGuard] Setup status check failed, assuming not initialized:', err); status = { initialized: true };
status = { initialized: false }; } else {
console.warn('[InitGuard] Setup status check failed, assuming not initialized:', err);
status = { initialized: false };
}
} }
const onSetup = location.pathname === '/setup'; const onSetup = location.pathname === '/setup';
+19 -1
View File
@@ -2,7 +2,7 @@ import { beforeEach, describe, expect, it } from 'vitest';
import { screen } from '@testing-library/react'; import { screen } from '@testing-library/react';
import { renderApp, mockAuthenticated, mockGuest } from '@/test/utils'; import { renderApp, mockAuthenticated, mockGuest } from '@/test/utils';
import { server } from '@/mocks/server'; import { server } from '@/mocks/server';
import { setupUninitializedHandlers } from '@/mocks/index'; import { setupUninitializedHandlers, setupNetworkErrorHandlers } from '@/mocks/index';
import { _resetSetupStatusCache } from '@/router'; import { _resetSetupStatusCache } from '@/router';
beforeEach(() => { beforeEach(() => {
@@ -53,6 +53,24 @@ describe('InitGuard (BR-U2-09, BR-U2-10)', () => {
expect(await screen.findByTestId('setup-submit-button')).toBeInTheDocument(); expect(await screen.findByTestId('setup-submit-button')).toBeInTheDocument();
}); });
it('shows login page (not setup) when backend is unreachable', async () => {
server.use(...setupNetworkErrorHandlers);
mockGuest();
renderApp('/login');
expect(await screen.findByTestId('login-form-submit-button')).toBeInTheDocument();
expect(screen.queryByTestId('setup-submit-button')).not.toBeInTheDocument();
});
it('redirects /setup to /login when backend is unreachable', async () => {
server.use(...setupNetworkErrorHandlers);
mockGuest();
renderApp('/setup');
expect(await screen.findByTestId('login-form-submit-button')).toBeInTheDocument();
expect(screen.queryByTestId('setup-submit-button')).not.toBeInTheDocument();
});
it('redirects /setup to /login when system is already initialized', async () => { it('redirects /setup to /login when system is already initialized', async () => {
// Default handlers return { initialized: true }. // Default handlers return { initialized: true }.
mockGuest(); mockGuest();