test: cover CorrespondentSuggestionsDropdown and PersonCard branches
CorrespondentSuggestionsDropdown: empty list still renders the static heading and 'Alle Korrespondenten' row, populated rows when not loading, loading hides correspondent rows, initials fallback (lastName-only when firstName is null), click + keyboard selection, Escape closes. PersonCard: full matrix of conditional UI — title visibility for PERSON vs non-PERSON, avatar initials path (firstName+lastName vs lastName-only fallback), PersonTypeBadge presence for non-PERSON types, alias, life dates, notes, and the canWrite=true/false branches that gate the edit link (Nora's authorization-rendering rule). 21 tests covering ~50 branches. Refs #496. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
120
frontend/src/routes/persons/[id]/PersonCard.svelte.test.ts
Normal file
120
frontend/src/routes/persons/[id]/PersonCard.svelte.test.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import { describe, it, expect, afterEach } from 'vitest';
|
||||
import { cleanup, render } from 'vitest-browser-svelte';
|
||||
import { page } from 'vitest/browser';
|
||||
import PersonCard from './PersonCard.svelte';
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
const basePerson = {
|
||||
id: 'p-1',
|
||||
firstName: 'Anna',
|
||||
lastName: 'Schmidt',
|
||||
displayName: 'Anna Schmidt',
|
||||
personType: 'PERSON' as const
|
||||
};
|
||||
|
||||
describe('PersonCard', () => {
|
||||
it('renders the displayName as the primary heading', async () => {
|
||||
render(PersonCard, { props: { person: basePerson, canWrite: false } });
|
||||
|
||||
await expect.element(page.getByRole('heading', { name: 'Anna Schmidt' })).toBeVisible();
|
||||
});
|
||||
|
||||
it('renders the title above the name when personType is PERSON and title is set', async () => {
|
||||
render(PersonCard, {
|
||||
props: { person: { ...basePerson, title: 'Frau Dr.' }, canWrite: false }
|
||||
});
|
||||
|
||||
await expect.element(page.getByText('Frau Dr.')).toBeVisible();
|
||||
});
|
||||
|
||||
it('omits the title for non-PERSON types even if title is set', async () => {
|
||||
render(PersonCard, {
|
||||
props: {
|
||||
person: { ...basePerson, personType: 'INSTITUTION', title: 'Frau Dr.' },
|
||||
canWrite: false
|
||||
}
|
||||
});
|
||||
|
||||
await expect.element(page.getByText('Frau Dr.')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the firstName/lastName initials inside the avatar for PERSON type', async () => {
|
||||
render(PersonCard, { props: { person: basePerson, canWrite: false } });
|
||||
|
||||
await expect.element(page.getByText('AS')).toBeVisible();
|
||||
});
|
||||
|
||||
it('falls back to lastName-only initials when firstName is missing', async () => {
|
||||
render(PersonCard, {
|
||||
props: {
|
||||
person: { ...basePerson, firstName: null, displayName: 'Schmidt' },
|
||||
canWrite: false
|
||||
}
|
||||
});
|
||||
|
||||
await expect.element(page.getByText('SS')).toBeVisible();
|
||||
});
|
||||
|
||||
it('renders the PersonTypeBadge for non-PERSON types', async () => {
|
||||
render(PersonCard, {
|
||||
props: {
|
||||
person: { ...basePerson, personType: 'INSTITUTION', displayName: 'Acme Inc.' },
|
||||
canWrite: false
|
||||
}
|
||||
});
|
||||
|
||||
await expect.element(page.getByText('Institution')).toBeVisible();
|
||||
});
|
||||
|
||||
it('omits the PersonTypeBadge for PERSON type', async () => {
|
||||
render(PersonCard, { props: { person: basePerson, canWrite: false } });
|
||||
|
||||
await expect.element(page.getByText('Institution')).not.toBeInTheDocument();
|
||||
await expect.element(page.getByText('Gruppe')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the alias in italic typography when alias is provided', async () => {
|
||||
render(PersonCard, {
|
||||
props: { person: { ...basePerson, alias: 'Annerl' }, canWrite: false }
|
||||
});
|
||||
|
||||
await expect.element(page.getByText(/Annerl/)).toBeVisible();
|
||||
});
|
||||
|
||||
it('renders the life-date range when birthYear or deathYear are present', async () => {
|
||||
render(PersonCard, {
|
||||
props: {
|
||||
person: { ...basePerson, birthYear: 1899, deathYear: 1972 },
|
||||
canWrite: false
|
||||
}
|
||||
});
|
||||
|
||||
await expect.element(page.getByText(/1899/)).toBeVisible();
|
||||
});
|
||||
|
||||
it('renders the notes section when notes are provided', async () => {
|
||||
render(PersonCard, {
|
||||
props: {
|
||||
person: { ...basePerson, notes: 'Wohnte in Berlin.' },
|
||||
canWrite: false
|
||||
}
|
||||
});
|
||||
|
||||
await expect.element(page.getByText('Wohnte in Berlin.')).toBeVisible();
|
||||
});
|
||||
|
||||
it('renders the edit link when canWrite is true', async () => {
|
||||
render(PersonCard, { props: { person: basePerson, canWrite: true } });
|
||||
|
||||
await expect
|
||||
.element(page.getByRole('link', { name: /bearbeiten/i }))
|
||||
.toHaveAttribute('href', '/persons/p-1/edit');
|
||||
});
|
||||
|
||||
it('does not render the edit link when canWrite is false', async () => {
|
||||
render(PersonCard, { props: { person: basePerson, canWrite: false } });
|
||||
|
||||
await expect.element(page.getByRole('link', { name: /bearbeiten/i })).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user