import { describe, it, expect, vi, afterEach } from 'vitest'; import { cleanup, render } from 'vitest-browser-svelte'; import { page } from 'vitest/browser'; import CorrespondentSuggestionsDropdown from './CorrespondentSuggestionsDropdown.svelte'; afterEach(cleanup); const corrA = { id: 'a', firstName: 'Anna', lastName: 'Schmidt', displayName: 'Anna Schmidt' }; const corrB = { id: 'b', firstName: null, lastName: 'Müller', displayName: 'Müller' }; describe('CorrespondentSuggestionsDropdown', () => { it('renders the heading and the "all correspondents" row even when the list is empty', async () => { render(CorrespondentSuggestionsDropdown, { props: { correspondents: [], loading: false, senderName: 'Anna', onselect: () => {}, onclose: () => {} } }); await expect.element(page.getByText('Häufigste Korrespondenten')).toBeVisible(); await expect.element(page.getByText('Alle Korrespondenten von Anna')).toBeVisible(); }); it('renders one row per correspondent when not loading', async () => { render(CorrespondentSuggestionsDropdown, { props: { correspondents: [corrA, corrB], loading: false, senderName: 'Anna', onselect: () => {}, onclose: () => {} } }); await expect.element(page.getByText('Anna Schmidt')).toBeVisible(); await expect.element(page.getByText('Müller')).toBeVisible(); }); it('hides correspondent rows while loading is true', async () => { render(CorrespondentSuggestionsDropdown, { props: { correspondents: [corrA], loading: true, senderName: 'Anna', onselect: () => {}, onclose: () => {} } }); await expect.element(page.getByText('Anna Schmidt')).not.toBeInTheDocument(); await expect.element(page.getByText('Häufigste Korrespondenten')).toBeVisible(); }); it('builds initials from firstName + lastName when available', async () => { render(CorrespondentSuggestionsDropdown, { props: { correspondents: [corrA], loading: false, senderName: 'Anna', onselect: () => {}, onclose: () => {} } }); await expect.element(page.getByText('AS')).toBeVisible(); }); it('falls back to the first two letters of lastName when firstName is missing', async () => { render(CorrespondentSuggestionsDropdown, { props: { correspondents: [corrB], loading: false, senderName: 'Anna', onselect: () => {}, onclose: () => {} } }); await expect.element(page.getByText('MÜ')).toBeVisible(); }); it('calls onselect with the correspondent id when a row is clicked', async () => { const onselect = vi.fn(); render(CorrespondentSuggestionsDropdown, { props: { correspondents: [corrA], loading: false, senderName: 'Anna', onselect, onclose: () => {} } }); await page.getByText('Anna Schmidt').click(); expect(onselect).toHaveBeenCalledWith('a'); }); it('calls onselect with an empty string when the "all correspondents" row is clicked', async () => { const onselect = vi.fn(); render(CorrespondentSuggestionsDropdown, { props: { correspondents: [], loading: false, senderName: 'Anna', onselect, onclose: () => {} } }); await page.getByText('Alle Korrespondenten von Anna').click(); expect(onselect).toHaveBeenCalledWith(''); }); it('calls onselect via Enter key on a focused row', async () => { const onselect = vi.fn(); render(CorrespondentSuggestionsDropdown, { props: { correspondents: [corrA], loading: false, senderName: 'Anna', onselect, onclose: () => {} } }); const row = (await page.getByText('Anna Schmidt').element()) as HTMLElement; row.focus(); row.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true })); expect(onselect).toHaveBeenCalledWith('a'); }); it('calls onclose when the Escape key is pressed', async () => { const onclose = vi.fn(); render(CorrespondentSuggestionsDropdown, { props: { correspondents: [corrA], loading: false, senderName: 'Anna', onselect: () => {}, onclose } }); const list = (await page.getByRole('listbox').element()) as HTMLElement; list.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true })); expect(onclose).toHaveBeenCalledOnce(); }); });