diff --git a/frontend/src/routes/korrespondenz/CorrespondenzEmptyState.svelte b/frontend/src/routes/korrespondenz/CorrespondenzEmptyState.svelte
index 0ff49bbf..9dae76ee 100644
--- a/frontend/src/routes/korrespondenz/CorrespondenzEmptyState.svelte
+++ b/frontend/src/routes/korrespondenz/CorrespondenzEmptyState.svelte
@@ -4,8 +4,7 @@ import { conv_empty_search_placeholder, conv_empty_recent_label } from '$lib/mes
interface RecentPerson {
id: string;
- firstName: string;
- lastName: string;
+ name: string;
}
interface Props {
@@ -110,9 +109,9 @@ onMount(() => {
class="flex h-4 w-4 shrink-0 items-center justify-center rounded-full bg-[#002850] text-[10px] text-white"
aria-hidden="true"
>
- {person.firstName[0]}{person.lastName[0]}
+ {person.name.charAt(0).toUpperCase()}
- {person.lastName}, {person.firstName}
+ {person.name}
{/each}
diff --git a/frontend/src/routes/korrespondenz/page.svelte.spec.ts b/frontend/src/routes/korrespondenz/page.svelte.spec.ts
index 85f18e63..b4e4ca7e 100644
--- a/frontend/src/routes/korrespondenz/page.svelte.spec.ts
+++ b/frontend/src/routes/korrespondenz/page.svelte.spec.ts
@@ -18,8 +18,15 @@ const baseData = {
filters: { senderId: '', receiverId: '', from: '', to: '', dir: 'DESC' as const }
};
+const withSender = {
+ ...baseData,
+ initialValues: { senderName: 'Hans Müller', receiverName: '' },
+ filters: { ...baseData.filters, senderId: 'p1' }
+};
+
const withPersons = {
...baseData,
+ initialValues: { senderName: 'Hans Müller', receiverName: 'Anna Schmidt' },
filters: { ...baseData.filters, senderId: 'p1', receiverId: 'p2' }
};
@@ -45,41 +52,120 @@ const withDocs = {
documents: [makeDoc()]
};
-// ─── Empty state ──────────────────────────────────────────────────────────────
+// ─── Empty state (no senderId) ────────────────────────────────────────────────
-describe('Conversations page – empty state', () => {
- it('shows the "select two persons" prompt when no persons are selected', async () => {
+describe('Korrespondenz page – empty state', () => {
+ it('shows the search heading when no person is selected', async () => {
render(Page, { data: baseData });
- await expect.element(page.getByText(/Wählen Sie zwei Personen aus/i)).toBeInTheDocument();
+ await expect.element(page.getByText(/Korrespondenz durchsuchen/i)).toBeInTheDocument();
});
- it('hides the swap button when no persons are selected', async () => {
+ it('shows the empty-search button', async () => {
render(Page, { data: baseData });
- // Button is always in the DOM (holds grid column width on desktop) but made invisible
- await expect.element(page.getByTestId('conv-swap-btn')).toHaveClass('invisible');
+ await expect.element(page.getByTestId('conv-empty-search')).toBeInTheDocument();
});
- it('does not show the new document link when no persons are selected', async () => {
+ it('does not show the new document link when no person is selected', async () => {
render(Page, { data: baseData });
await expect.element(page.getByTestId('conv-new-doc-link')).not.toBeInTheDocument();
});
+
+ it('does not show a year divider when no person is selected', async () => {
+ render(Page, { data: baseData });
+ await expect.element(page.getByTestId('year-divider')).not.toBeInTheDocument();
+ });
+});
+
+// ─── Recent persons chips ─────────────────────────────────────────────────────
+
+describe('Korrespondenz page – recent persons', () => {
+ it('shows recent person chips from localStorage', async () => {
+ localStorage.setItem(
+ 'korrespondenz_recent_persons',
+ JSON.stringify([{ id: 'r1', name: 'Clara Braun' }])
+ );
+ render(Page, { data: baseData });
+ await expect.element(page.getByText('Clara Braun')).toBeInTheDocument();
+ localStorage.removeItem('korrespondenz_recent_persons');
+ });
+
+ it('does not crash when localStorage contains corrupt JSON', async () => {
+ localStorage.setItem('korrespondenz_recent_persons', '}{not valid json');
+ render(Page, { data: baseData });
+ // Empty state heading is still shown — no chip list crash
+ await expect.element(page.getByText(/Korrespondenz durchsuchen/i)).toBeInTheDocument();
+ localStorage.removeItem('korrespondenz_recent_persons');
+ });
+});
+
+// ─── Single-person hint bar ───────────────────────────────────────────────────
+
+describe('Korrespondenz page – single-person hint bar', () => {
+ it('shows hint bar when only senderId is set', async () => {
+ render(Page, { data: withSender });
+ await expect.element(page.getByText(/Alle Briefe von Hans Müller/i)).toBeInTheDocument();
+ });
+
+ it('does not show hint bar when both persons are set', async () => {
+ render(Page, { data: { ...withPersons, documents: [makeDoc()] } });
+ await expect.element(page.getByText(/Alle Briefe von Hans Müller/i)).not.toBeInTheDocument();
+ });
+
+ it('does not show hint bar when no person is set', async () => {
+ render(Page, { data: baseData });
+ await expect.element(page.getByText(/Alle Briefe von/i)).not.toBeInTheDocument();
+ });
+});
+
+// ─── Filter controls disabled state ──────────────────────────────────────────
+
+describe('Korrespondenz page – filter strip Row 2 disabled state', () => {
+ it('renders filter controls with aria-disabled when no senderId', async () => {
+ render(Page, { data: baseData });
+ const strip = document.querySelector('[aria-disabled="true"]');
+ expect(strip).not.toBeNull();
+ });
+});
+
+// ─── Strip letter count ───────────────────────────────────────────────────────
+
+describe('Korrespondenz page – strip letter count', () => {
+ it('shows 0 Briefe when senderId is set but no documents', async () => {
+ render(Page, { data: withSender });
+ await expect.element(page.getByTestId('conv-strip-count')).toHaveTextContent('0 Briefe');
+ });
+
+ it('shows correct count when documents are loaded', async () => {
+ render(Page, { data: { ...withPersons, documents: [makeDoc()] } });
+ await expect.element(page.getByTestId('conv-strip-count')).toHaveTextContent('1 Briefe');
+ });
});
// ─── No results ───────────────────────────────────────────────────────────────
-describe('Conversations page – no results', () => {
- it('shows "no documents found" when both persons are selected but there are no documents', async () => {
- render(Page, { data: withPersons });
+describe('Korrespondenz page – no results', () => {
+ it('shows "no documents found" when a person is selected but there are no documents', async () => {
+ render(Page, { data: withSender });
await expect.element(page.getByText(/Keine Dokumente gefunden/i)).toBeInTheDocument();
});
});
// ─── Swap button ──────────────────────────────────────────────────────────────
-describe('Conversations page – swap button', () => {
- it('shows the swap button when both persons are selected', async () => {
+describe('Korrespondenz page – swap button', () => {
+ it('swap button is invisible when only one person is set', async () => {
+ render(Page, { data: withSender });
+ const btn = document.querySelector('[data-testid="conv-swap-btn"]');
+ expect(btn).not.toBeNull();
+ // opacity-0 is applied via class when swapVisible is false
+ expect(btn!.className).toMatch(/opacity-0/);
+ });
+
+ it('swap button is visible when both persons are set', async () => {
render(Page, { data: withPersons });
- await expect.element(page.getByTestId('conv-swap-btn')).not.toHaveClass('invisible');
+ const btn = document.querySelector('[data-testid="conv-swap-btn"]');
+ expect(btn).not.toBeNull();
+ expect(btn!.className).not.toMatch(/opacity-0/);
});
it('calls goto with swapped sender and receiver when clicked', async () => {
@@ -92,28 +178,9 @@ describe('Conversations page – swap button', () => {
});
});
-// ─── Summary ──────────────────────────────────────────────────────────────────
-
-describe('Conversations page – summary', () => {
- it('shows document count and year range when documents are loaded', async () => {
- const data = {
- ...withPersons,
- documents: [
- makeDoc({ documentDate: '1923-04-12' }),
- makeDoc({ id: 'd2', documentDate: '1965-08-03' })
- ]
- };
- render(Page, { data });
- const summary = page.getByTestId('conv-summary');
- await expect.element(summary).toHaveTextContent('2');
- await expect.element(summary).toHaveTextContent('1923');
- await expect.element(summary).toHaveTextContent('1965');
- });
-});
-
// ─── Year dividers ────────────────────────────────────────────────────────────
-describe('Conversations page – year dividers', () => {
+describe('Korrespondenz page – year dividers', () => {
it('renders a year divider for the first document', async () => {
render(Page, { data: withDocs });
await expect.element(page.getByTestId('year-divider').first()).toHaveTextContent('1923');
@@ -141,7 +208,6 @@ describe('Conversations page – year dividers', () => {
]
};
render(Page, { data });
- // Only one divider for 1923; 1965 divider should not appear
await expect.element(page.getByTestId('year-divider').first()).toHaveTextContent('1923');
await expect.element(page.getByTestId('year-divider').nth(1)).not.toBeInTheDocument();
});
@@ -149,12 +215,21 @@ describe('Conversations page – year dividers', () => {
// ─── New document link ────────────────────────────────────────────────────────
-describe('Conversations page – new document link', () => {
- it('shows the link with correct href for a write user', async () => {
+describe('Korrespondenz page – new document link', () => {
+ it('shows the link with correct href for a write user (bilateral)', async () => {
render(Page, { data: { ...withDocs, canWrite: true } });
const link = page.getByTestId('conv-new-doc-link');
await expect.element(link).toBeInTheDocument();
- await expect.element(link).toHaveAttribute('href', '/documents/new?senderId=p1&receiverId=p2');
+ await expect.element(link).toHaveAttribute('href', expect.stringContaining('senderId=p1'));
+ await expect.element(link).toHaveAttribute('href', expect.stringContaining('receiverId=p2'));
+ });
+
+ it('shows the link with correct href for single-person mode', async () => {
+ render(Page, { data: { ...withSender, documents: [makeDoc()], canWrite: true } });
+ const link = page.getByTestId('conv-new-doc-link');
+ await expect.element(link).toBeInTheDocument();
+ await expect.element(link).toHaveAttribute('href', expect.stringContaining('senderId=p1'));
+ await expect.element(link).not.toHaveAttribute('href', expect.stringContaining('receiverId'));
});
it('hides the link for a read-only user', async () => {