From 7d70add709b7acc70bdfb359908306d9796d621d Mon Sep 17 00:00:00 2001 From: Marcel Date: Sun, 10 May 2026 02:02:18 +0200 Subject: [PATCH] test(geschichte): cover GeschichtenCard branches Empty list early return, populated section, write-action link gated on canWrite, visible-cap of 3, footer show-all link visibility based on overflow, author name vs email fallback. 9 tests covering ~25 of GeschichtenCard's branches. Refs #496. Co-Authored-By: Claude Sonnet 4.6 --- .../geschichte/GeschichtenCard.svelte.test.ts | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 frontend/src/lib/geschichte/GeschichtenCard.svelte.test.ts diff --git a/frontend/src/lib/geschichte/GeschichtenCard.svelte.test.ts b/frontend/src/lib/geschichte/GeschichtenCard.svelte.test.ts new file mode 100644 index 00000000..e3212cbf --- /dev/null +++ b/frontend/src/lib/geschichte/GeschichtenCard.svelte.test.ts @@ -0,0 +1,109 @@ +import { describe, it, expect, afterEach } from 'vitest'; +import { cleanup, render } from 'vitest-browser-svelte'; +import { page } from 'vitest/browser'; +import GeschichtenCard from './GeschichtenCard.svelte'; + +afterEach(cleanup); + +const makeGeschichte = (overrides: Record = {}) => ({ + id: 'g1', + title: 'Reise nach Berlin', + body: '

Brief text

', + publishedAt: '2026-04-15T10:00:00Z', + author: { firstName: 'Anna', lastName: 'Schmidt', email: 'a@b' } as unknown, + ...overrides +}); + +const baseProps = (overrides: Record = {}) => ({ + geschichten: [] as ReturnType[], + personId: 'p-1', + personName: 'Anna Schmidt', + canWrite: false, + ...overrides +}); + +describe('GeschichtenCard', () => { + it('renders nothing when geschichten is empty', async () => { + render(GeschichtenCard, { props: baseProps() }); + + expect(document.querySelector('section')).toBeNull(); + }); + + it('renders the section when at least one geschichte is present', async () => { + render(GeschichtenCard, { props: baseProps({ geschichten: [makeGeschichte()] }) }); + + await expect.element(page.getByRole('heading', { name: /geschichten/i })).toBeVisible(); + }); + + it('shows the write-action link when canWrite is true', async () => { + render(GeschichtenCard, { + props: baseProps({ geschichten: [makeGeschichte()], canWrite: true }) + }); + + await expect + .element(page.getByRole('link', { name: /geschichte schreiben/i })) + .toHaveAttribute('href', '/geschichten/new?personId=p-1'); + }); + + it('hides the write-action link when canWrite is false', async () => { + render(GeschichtenCard, { props: baseProps({ geschichten: [makeGeschichte()] }) }); + + await expect + .element(page.getByRole('link', { name: /geschichte schreiben/i })) + .not.toBeInTheDocument(); + }); + + it('limits visible geschichten to 3', async () => { + const geschichten = Array.from({ length: 5 }, (_, i) => + makeGeschichte({ id: `g${i}`, title: `Geschichte ${i + 1}` }) + ); + render(GeschichtenCard, { props: baseProps({ geschichten }) }); + + await expect.element(page.getByText('Geschichte 1')).toBeVisible(); + await expect.element(page.getByText('Geschichte 3')).toBeVisible(); + await expect.element(page.getByText('Geschichte 4')).not.toBeInTheDocument(); + }); + + it('renders the show-all link in the footer when there are 3 or more', async () => { + const geschichten = Array.from({ length: 3 }, (_, i) => + makeGeschichte({ id: `g${i}`, title: `g${i}` }) + ); + render(GeschichtenCard, { props: baseProps({ geschichten }) }); + + await expect + .element(page.getByRole('link', { name: /alle geschichten zu anna schmidt/i })) + .toHaveAttribute('href', '/geschichten?personId=p-1'); + }); + + it('hides the show-all footer when fewer than 3 geschichten', async () => { + render(GeschichtenCard, { + props: baseProps({ + geschichten: [makeGeschichte({ id: 'g1' }), makeGeschichte({ id: 'g2', title: 'Two' })] + }) + }); + + await expect + .element(page.getByRole('link', { name: /alle geschichten zu/i })) + .not.toBeInTheDocument(); + }); + + it('renders the author full name when both first and last names are set', async () => { + render(GeschichtenCard, { props: baseProps({ geschichten: [makeGeschichte()] }) }); + + await expect.element(page.getByText(/Anna Schmidt/)).toBeVisible(); + }); + + it('falls back to author email when no name', async () => { + render(GeschichtenCard, { + props: baseProps({ + geschichten: [ + makeGeschichte({ + author: { firstName: undefined, lastName: undefined, email: 'fallback@x' } + }) + ] + }) + }); + + await expect.element(page.getByText(/fallback@x/)).toBeVisible(); + }); +});