import { render, screen, waitFor } from '@testing-library/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { describe, expect, it, vi } from 'vitest'; import { App } from '@/App'; import type { InstanceMeta } from '@/api/meta'; import '@/i18n'; const meta: InstanceMeta = { name: 'glchat', version: 'v0.1.0-test', commit: 'deadbee', build_date: '2026-09-19T00:00:00Z', api_version: 'v1', base_url: 'https://gl.localhost', files_url: 'https://files.gl.localhost', gateway_url: 'wss://gl.localhost/gateway', rtc_path: '/rtc', max_upload_size: 26214400, features: { registration_enabled: true, anti_bot_enabled: false, voice_enabled: false, web_push_enabled: false, oauth_enabled: false, passkeys_enabled: false, }, }; const readyBody = { status: 'ready', version: 'test', checks: { database: 'ok' } }; function json(body: unknown, status = 200): Response { return new Response(JSON.stringify(body), { status, headers: { 'Content-Type': 'application/json' }, }); } function renderApp() { const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, }); return render( , ); } describe('App', () => { it('renders instance metadata from the API', async () => { vi.stubGlobal( 'fetch', vi.fn((input: RequestInfo | URL) => { const url = input instanceof Request ? input.url : String(input); return Promise.resolve(url.endsWith('/api/v1/meta') ? json(meta) : json(readyBody)); }), ); renderApp(); await waitFor(() => { expect(screen.getByText('v0.1.0-test')).toBeInTheDocument(); }); expect(screen.getByText('v1')).toBeInTheDocument(); expect(screen.getByText('25 MB')).toBeInTheDocument(); expect(screen.getByTestId('connection-state')).toHaveTextContent('Сервер доступен'); }); it('localizes a server error by its code and offers a retry', async () => { const fetchMock = vi.fn(() => json({ error: { code: 'internal.error', message: 'boom' } }, 500), ); vi.stubGlobal('fetch', fetchMock); renderApp(); await waitFor( () => { expect(screen.getByRole('alert')).toHaveTextContent('Внутренняя ошибка сервера.'); }, { timeout: 5000 }, ); expect(screen.getByRole('button', { name: 'Повторить' })).toBeInTheDocument(); }); it('falls back to a network message when the server is unreachable', async () => { vi.stubGlobal('fetch', vi.fn().mockRejectedValue(new TypeError('Failed to fetch'))); renderApp(); await waitFor( () => { expect(screen.getByRole('alert')).toHaveTextContent('Сервер не отвечает'); }, { timeout: 5000 }, ); expect(screen.getByTestId('connection-state')).toHaveTextContent('Сервер недоступен'); }); });