import { describe, it, expect, afterEach } from 'vitest'; import { cleanup, render } from 'vitest-browser-svelte'; import { page } from 'vitest/browser'; import PersonChip from './PersonChip.svelte'; afterEach(cleanup); const personWithFirstName = { id: 'p-1', firstName: 'Helene', lastName: 'Schmidt', displayName: 'Helene Schmidt' }; const personLastNameOnly = { id: 'p-2', firstName: null, lastName: 'Müller', displayName: 'Müller' }; describe('PersonChip', () => { it('renders the full display name when abbreviated is false', async () => { render(PersonChip, { props: { person: personWithFirstName, abbreviated: false } }); await expect.element(page.getByText('Helene Schmidt')).toBeVisible(); }); it('renders the abbreviated name when abbreviated is true', async () => { render(PersonChip, { props: { person: personWithFirstName, abbreviated: true } }); await expect.element(page.getByText('H. Schmidt')).toBeVisible(); }); it('falls back to lastName-only when the person has no firstName', async () => { render(PersonChip, { props: { person: personLastNameOnly, abbreviated: true } }); await expect.element(page.getByText('Müller')).toBeVisible(); }); it('links to the person detail route by id', async () => { render(PersonChip, { props: { person: personWithFirstName, abbreviated: false } }); await expect .element(page.getByRole('link', { name: /helene schmidt/i })) .toHaveAttribute('href', '/persons/p-1'); }); it('renders initials inside the avatar circle', async () => { render(PersonChip, { props: { person: personWithFirstName, abbreviated: false } }); await expect.element(page.getByText('HS')).toBeVisible(); }); it('uses a deterministic avatar background color derived from the person id', async () => { render(PersonChip, { props: { person: personWithFirstName, abbreviated: false } }); const initials = await page.getByText('HS').element(); const style = (initials as HTMLElement).getAttribute('style') ?? ''; expect(style).toMatch(/background-color:\s*(rgb\(|#)/i); }); });