import { describe, it, expect, vi, afterEach } from 'vitest'; import { cleanup, render } from 'vitest-browser-svelte'; import { page } from 'vitest/browser'; import CorrespondenzPersonBar from './CorrespondenzPersonBar.svelte'; afterEach(cleanup); const baseProps = (overrides: Record = {}) => ({ senderId: '', receiverId: '', initialSenderName: '', initialReceiverName: '', sortDir: 'DESC', showAdvanced: false, documentCount: 0, onapplyFilters: () => {}, onswapPersons: () => {}, ontoggleSort: () => {}, ontoggleAdvanced: () => {}, ...overrides }); describe('CorrespondenzPersonBar', () => { it('renders the two PersonTypeahead inputs', async () => { render(CorrespondenzPersonBar, { props: baseProps() }); const inputs = document.querySelectorAll('input'); expect(inputs.length).toBeGreaterThanOrEqual(2); }); it('hides the swap button when only one person is set', async () => { render(CorrespondenzPersonBar, { props: baseProps({ senderId: 'p1' }) }); const swap = document.querySelector('[data-testid="conv-swap-btn"]') as HTMLElement; expect(swap.classList.contains('opacity-0')).toBe(true); expect(swap.tabIndex).toBe(-1); }); it('shows the swap button when both senderId and receiverId are set', async () => { render(CorrespondenzPersonBar, { props: baseProps({ senderId: 'p1', receiverId: 'p2' }) }); const swap = document.querySelector('[data-testid="conv-swap-btn"]') as HTMLElement; expect(swap.classList.contains('opacity-0')).toBe(false); expect(swap.tabIndex).toBe(0); }); it('renders the "Neueste" label when sortDir is DESC', async () => { render(CorrespondenzPersonBar, { props: baseProps({ sortDir: 'DESC' }) }); await expect.element(page.getByText('Neueste')).toBeVisible(); }); it('renders the "Älteste" label when sortDir is ASC', async () => { render(CorrespondenzPersonBar, { props: baseProps({ sortDir: 'ASC' }) }); await expect.element(page.getByText('Älteste')).toBeVisible(); }); it('marks the sort button as aria-pressed when sortDir is ASC', async () => { render(CorrespondenzPersonBar, { props: baseProps({ sortDir: 'ASC' }) }); const sort = document.querySelector('[data-testid="conv-sort-btn"]') as HTMLElement; expect(sort.getAttribute('aria-pressed')).toBe('true'); }); it('renders the document count', async () => { render(CorrespondenzPersonBar, { props: baseProps({ documentCount: 42 }) }); await expect.element(page.getByText('42 Briefe')).toBeVisible(); }); it('calls ontoggleSort when the sort button is clicked', async () => { const ontoggleSort = vi.fn(); render(CorrespondenzPersonBar, { props: baseProps({ ontoggleSort }) }); const sort = document.querySelector('[data-testid="conv-sort-btn"]') as HTMLElement; sort.click(); expect(ontoggleSort).toHaveBeenCalledOnce(); }); it('calls onswapPersons when the swap button is clicked', async () => { const onswapPersons = vi.fn(); render(CorrespondenzPersonBar, { props: baseProps({ senderId: 'p1', receiverId: 'p2', onswapPersons }) }); const swap = document.querySelector('[data-testid="conv-swap-btn"]') as HTMLElement; swap.click(); expect(onswapPersons).toHaveBeenCalledOnce(); }); it('opens the suggestions dropdown on receiver focus when a senderId is set', async () => { const fetchSpy = vi.spyOn(globalThis, 'fetch').mockResolvedValue( new Response(JSON.stringify([{ id: 'p3', firstName: 'Carl', lastName: 'Brandt' }]), { status: 200, headers: { 'Content-Type': 'application/json' } }) ); try { render(CorrespondenzPersonBar, { props: baseProps({ senderId: 'p1', receiverId: '' }) }); // Find the second PersonTypeahead input (Korrespondent) and trigger focus event const inputs = document.querySelectorAll('input[type="text"]'); const corrInput = inputs[inputs.length - 1] as HTMLInputElement; corrInput.dispatchEvent(new Event('focus', { bubbles: true })); // Confirm the typeahead fired the suggestions fetch. await vi.waitFor(() => expect(fetchSpy).toHaveBeenCalled()); } finally { fetchSpy.mockRestore(); } }); it('does not show advanced filter chevron rotation when showAdvanced is false', async () => { render(CorrespondenzPersonBar, { props: baseProps({ showAdvanced: false }) }); // The filter toggle button has a chevron — should NOT be rotated const buttons = document.querySelectorAll('button'); const filterBtn = Array.from(buttons).find((b) => b.textContent?.toLowerCase().includes('filter') ); const chevron = filterBtn?.querySelector('img'); expect(chevron?.getAttribute('class')).not.toContain('rotate-180'); }); it('rotates the filter chevron when showAdvanced is true', async () => { render(CorrespondenzPersonBar, { props: baseProps({ showAdvanced: true }) }); const buttons = document.querySelectorAll('button'); const filterBtn = Array.from(buttons).find((b) => b.textContent?.toLowerCase().includes('filter') ); const chevron = filterBtn?.querySelector('img'); expect(chevron?.getAttribute('class')).toContain('rotate-180'); }); });