diff --git a/frontend/src/routes/search/SmartSearchStatus.svelte b/frontend/src/routes/search/SmartSearchStatus.svelte new file mode 100644 index 00000000..80a0a1d5 --- /dev/null +++ b/frontend/src/routes/search/SmartSearchStatus.svelte @@ -0,0 +1,69 @@ + + +{#if status === 'loading'} +
+ +

{m.search_loading_nl()}

+

+ {m.search_loading_nl_sub()} +

+
+{:else if status === 'error'} + +{/if} diff --git a/frontend/src/routes/search/SmartSearchStatus.svelte.spec.ts b/frontend/src/routes/search/SmartSearchStatus.svelte.spec.ts new file mode 100644 index 00000000..605576d0 --- /dev/null +++ b/frontend/src/routes/search/SmartSearchStatus.svelte.spec.ts @@ -0,0 +1,60 @@ +import { describe, expect, it, vi, afterEach } from 'vitest'; +import { cleanup, render } from 'vitest-browser-svelte'; +import { page } from 'vitest/browser'; +import SmartSearchStatus from './SmartSearchStatus.svelte'; + +afterEach(() => { + cleanup(); + vi.restoreAllMocks(); +}); + +describe('SmartSearchStatus', () => { + it('renders a role="status" loading panel with the loading title', async () => { + render(SmartSearchStatus, { status: 'loading' }); + const status = page.getByRole('status'); + await expect.element(status).toBeInTheDocument(); + await expect.element(status).toHaveTextContent('Archiv wird befragt'); + }); + + it('hides the loading panel once the status changes away from loading', async () => { + const { rerender } = render(SmartSearchStatus, { status: 'loading' }); + await expect.element(page.getByRole('status')).toBeInTheDocument(); + await rerender({ status: 'error', errorCode: 'SMART_SEARCH_UNAVAILABLE' }); + await expect.element(page.getByRole('status')).not.toBeInTheDocument(); + }); + + it('renders the 503 panel with title, body and a switch-to-keyword button', async () => { + render(SmartSearchStatus, { + status: 'error', + errorCode: 'SMART_SEARCH_UNAVAILABLE', + onSwitchToKeyword: vi.fn() + }); + await expect.element(page.getByText('Intelligente Suche nicht verfügbar')).toBeInTheDocument(); + await expect + .element(page.getByRole('button', { name: /Volltextsuche wechseln/ })) + .toBeInTheDocument(); + }); + + it('invokes onSwitchToKeyword when the 503 fallback button is clicked', async () => { + const onSwitchToKeyword = vi.fn(); + render(SmartSearchStatus, { + status: 'error', + errorCode: 'SMART_SEARCH_UNAVAILABLE', + onSwitchToKeyword + }); + await page.getByRole('button', { name: /Volltextsuche wechseln/ }).click(); + expect(onSwitchToKeyword).toHaveBeenCalledOnce(); + }); + + it('renders the 429 panel with title and body but no switch-to-keyword button', async () => { + render(SmartSearchStatus, { + status: 'error', + errorCode: 'SMART_SEARCH_RATE_LIMITED', + onSwitchToKeyword: vi.fn() + }); + await expect.element(page.getByText('Zu viele Anfragen')).toBeInTheDocument(); + await expect + .element(page.getByRole('button', { name: /Volltextsuche wechseln/ })) + .not.toBeInTheDocument(); + }); +});