From 273bf5e5fa272b6098027de2640612b6215aa464 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sat, 9 May 2026 20:00:15 +0200 Subject: [PATCH] test(person): add PersonChip browser tests Covers the abbreviated/full name branches, the firstName-null fallback path, link href derivation from person id, initials rendering, and the deterministic avatar palette colour. Six tests, six branches hit. Refs #496. Co-Authored-By: Claude Sonnet 4.6 --- .../src/lib/person/PersonChip.svelte.test.ts | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 frontend/src/lib/person/PersonChip.svelte.test.ts diff --git a/frontend/src/lib/person/PersonChip.svelte.test.ts b/frontend/src/lib/person/PersonChip.svelte.test.ts new file mode 100644 index 00000000..30b60b8b --- /dev/null +++ b/frontend/src/lib/person/PersonChip.svelte.test.ts @@ -0,0 +1,62 @@ +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); + }); +});