From 45c97a84d8ef300974d971fe877173d22d4cb22e Mon Sep 17 00:00:00 2001 From: Marcel Date: Sun, 10 May 2026 01:39:35 +0200 Subject: [PATCH] test(person/genealogy): cover StammbaumCard branches Heading, family-member toggle visibility tied to canWrite, aria-checked matrix, in-tree banner gating, relationship-error alert, empty placeholder, no-derived-relationships path, AddRelationshipForm mounting tied to canWrite. 10 tests covering ~25 branches. Refs #496. Co-Authored-By: Claude Sonnet 4.6 --- .../genealogy/StammbaumCard.svelte.test.ts | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 frontend/src/lib/person/genealogy/StammbaumCard.svelte.test.ts diff --git a/frontend/src/lib/person/genealogy/StammbaumCard.svelte.test.ts b/frontend/src/lib/person/genealogy/StammbaumCard.svelte.test.ts new file mode 100644 index 00000000..e04c38f7 --- /dev/null +++ b/frontend/src/lib/person/genealogy/StammbaumCard.svelte.test.ts @@ -0,0 +1,89 @@ +import { describe, it, expect, afterEach } from 'vitest'; +import { cleanup, render } from 'vitest-browser-svelte'; +import { page } from 'vitest/browser'; +import StammbaumCard from './StammbaumCard.svelte'; + +afterEach(cleanup); + +const baseProps = (overrides: Record = {}) => ({ + personId: 'p-1', + familyMember: false, + relationships: [] as unknown[], + inferredRelationships: [] as unknown[], + canWrite: false, + relationshipError: null as string | null, + ...overrides +}); + +describe('StammbaumCard', () => { + it('renders the heading', async () => { + render(StammbaumCard, { props: baseProps() }); + + await expect + .element(page.getByRole('heading', { name: /stammbaum & beziehungen/i })) + .toBeVisible(); + }); + + it('renders the family-member toggle when canWrite is true', async () => { + render(StammbaumCard, { props: baseProps({ canWrite: true }) }); + + await expect.element(page.getByRole('switch')).toBeVisible(); + }); + + it('omits the family-member toggle when canWrite is false', async () => { + render(StammbaumCard, { props: baseProps() }); + + await expect.element(page.getByRole('switch')).not.toBeInTheDocument(); + }); + + it('marks the toggle as aria-checked=true when familyMember is true', async () => { + render(StammbaumCard, { props: baseProps({ canWrite: true, familyMember: true }) }); + + await expect.element(page.getByRole('switch')).toHaveAttribute('aria-checked', 'true'); + }); + + it('renders the in-tree banner when familyMember is true', async () => { + render(StammbaumCard, { props: baseProps({ familyMember: true }) }); + + await expect.element(page.getByText('Erscheint im Stammbaum')).toBeVisible(); + await expect + .element(page.getByRole('link', { name: /ansehen/i })) + .toHaveAttribute('href', '/stammbaum?focus=p-1'); + }); + + it('hides the in-tree banner when familyMember is false', async () => { + render(StammbaumCard, { props: baseProps() }); + + await expect.element(page.getByText('Erscheint im Stammbaum')).not.toBeInTheDocument(); + }); + + it('shows the relationshipError alert when set', async () => { + render(StammbaumCard, { + props: baseProps({ relationshipError: 'Beziehung konnte nicht gespeichert werden.' }) + }); + + await expect + .element(page.getByText('Beziehung konnte nicht gespeichert werden.')) + .toBeVisible(); + }); + + it('renders the empty placeholder for direct relationships when none exist', async () => { + render(StammbaumCard, { props: baseProps() }); + + await expect.element(page.getByText('Noch keine Beziehungen bekannt.')).toBeVisible(); + }); + + it('hides the inferred-relationships disclosure when there are none', async () => { + render(StammbaumCard, { props: baseProps() }); + + await expect.element(page.getByText('Abgeleitete Beziehungen')).not.toBeInTheDocument(); + }); + + it('renders the AddRelationshipForm when canWrite is true', async () => { + render(StammbaumCard, { props: baseProps({ canWrite: true }) }); + + // AddRelationshipForm renders interactive elements + const buttons = document.querySelectorAll('button'); + expect(buttons.length).toBeGreaterThan(1); + }); +});