import { describe, it, expect, afterEach, vi, beforeEach } from 'vitest'; import { cleanup, render } from 'vitest-browser-svelte'; import { page } from 'vitest/browser'; import StammbaumSidePanel from './StammbaumSidePanel.svelte'; vi.mock('$app/navigation', () => ({ invalidateAll: vi.fn() })); vi.mock('$lib/components/PersonTypeahead.svelte', () => ({ default: () => null })); const makeNode = () => ({ id: 'person-1', displayName: 'Alice Müller', birthYear: 1900, deathYear: null, familyMember: true }); function stubFetch(directRels: unknown[] = [], inferredRels: unknown[] = []) { let callCount = 0; vi.stubGlobal( 'fetch', vi.fn().mockImplementation(() => { callCount++; const body = callCount % 2 === 1 ? directRels : inferredRels; return Promise.resolve({ ok: true, json: () => Promise.resolve(body) }); }) ); } beforeEach(() => stubFetch()); afterEach(() => { cleanup(); vi.unstubAllGlobals(); }); describe('StammbaumSidePanel', () => { it('calls onClose when dismiss button is clicked', async () => { const onClose = vi.fn(); render(StammbaumSidePanel, { node: makeNode(), onClose, canWrite: false }); await expect.element(page.getByRole('button', { name: 'Schließen' })).toBeInTheDocument(); const btn = [...document.querySelectorAll('button')].find( (b) => b.getAttribute('aria-label') === 'Schließen' ); btn!.click(); expect(onClose).toHaveBeenCalledOnce(); }); it('renders the person displayName as heading', async () => { render(StammbaumSidePanel, { node: makeNode(), onClose: vi.fn(), canWrite: false }); await expect.element(page.getByText('Alice Müller')).toBeInTheDocument(); }); it('shows empty-relationships message when no direct relationships are loaded', async () => { render(StammbaumSidePanel, { node: makeNode(), onClose: vi.fn(), canWrite: false }); await expect.element(page.getByText('Noch keine Beziehungen bekannt.')).toBeInTheDocument(); }); it('shows loading indicator while fetching', async () => { let resolveFirst: (v: unknown) => void; vi.stubGlobal( 'fetch', vi.fn().mockImplementation( () => new Promise((resolve) => { resolveFirst = resolve; }) ) ); render(StammbaumSidePanel, { node: makeNode(), onClose: vi.fn(), canWrite: false }); await expect.element(page.getByText('…')).toBeInTheDocument(); resolveFirst!({ ok: true, json: () => Promise.resolve([]) }); }); });