test(activity): cover DashboardActivityFeed branches

Caption + show-all link, empty/non-empty conditional, actor avatar
vs question-mark fallback, rollup count badge presence, youMentioned
badge, verbMap entries (TEXT_SAVED, FILE_UPLOADED), unknown-kind
fallback, rollup time range, actor name vs initials fallback,
document href construction.

13 tests, ~50 branches.

Refs #496.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-05-10 03:02:46 +02:00
committed by marcel
parent c0d0638f2b
commit 23bae62248

View File

@@ -0,0 +1,161 @@
import { describe, it, expect, afterEach } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { page } from 'vitest/browser';
import DashboardActivityFeed from './DashboardActivityFeed.svelte';
import type { components } from '$lib/generated/api';
type ActivityFeedItemDTO = components['schemas']['ActivityFeedItemDTO'];
afterEach(cleanup);
const baseItem = (overrides: Partial<ActivityFeedItemDTO> = {}): ActivityFeedItemDTO =>
({
kind: 'TEXT_SAVED',
documentId: 'doc-1',
documentTitle: 'Brief 1899',
actor: {
id: 'u-1',
name: 'Anna Schmidt',
initials: 'AS',
color: '#336699'
},
count: 1,
happenedAt: '2026-04-14T14:02:00Z',
happenedAtUntil: null,
youMentioned: false,
...overrides
}) as ActivityFeedItemDTO;
describe('DashboardActivityFeed', () => {
it('renders the feed caption and show-all link', async () => {
render(DashboardActivityFeed, { props: { feed: [] } });
await expect.element(page.getByText('Kommentare & Aktivität')).toBeVisible();
const link = document.querySelector('a[href="/aktivitaeten"]');
expect(link).not.toBeNull();
});
it('renders nothing in the list when the feed is empty', async () => {
render(DashboardActivityFeed, { props: { feed: [] } });
const lists = document.querySelectorAll('ul');
expect(lists.length).toBe(0);
});
it('renders one row per feed item with the actor initials', async () => {
render(DashboardActivityFeed, {
props: {
feed: [baseItem(), baseItem({ documentId: 'doc-2', documentTitle: 'Brief 1900' })]
}
});
const items = document.querySelectorAll('li');
expect(items.length).toBe(2);
expect(document.body.textContent).toContain('AS');
});
it('renders the question-mark badge when no actor is set', async () => {
render(DashboardActivityFeed, {
props: { feed: [baseItem({ actor: null as unknown as undefined })] }
});
const li = document.querySelector('li');
expect(li?.textContent).toContain('?');
});
it('renders the rollup count badge when count > 1', async () => {
render(DashboardActivityFeed, {
props: { feed: [baseItem({ count: 5 })] }
});
const badge = document.querySelector('[data-testid="feed-rollup-count"]');
expect(badge?.textContent?.trim()).toBe('5');
});
it('omits the rollup count badge when count is 1', async () => {
render(DashboardActivityFeed, { props: { feed: [baseItem({ count: 1 })] } });
const badge = document.querySelector('[data-testid="feed-rollup-count"]');
expect(badge).toBeNull();
});
it('renders the "für dich" badge when youMentioned is true', async () => {
render(DashboardActivityFeed, {
props: { feed: [baseItem({ youMentioned: true })] }
});
await expect.element(page.getByText(/für dich/i)).toBeVisible();
});
it('maps the kind enum to a localized verb (TEXT_SAVED)', async () => {
render(DashboardActivityFeed, {
props: { feed: [baseItem({ kind: 'TEXT_SAVED' as ActivityFeedItemDTO['kind'] })] }
});
expect(document.body.textContent).toContain('hat Text gespeichert in');
});
it('maps the kind enum to a localized verb (FILE_UPLOADED)', async () => {
render(DashboardActivityFeed, {
props: { feed: [baseItem({ kind: 'FILE_UPLOADED' as ActivityFeedItemDTO['kind'] })] }
});
expect(document.body.textContent).toContain('hat eine Datei hochgeladen');
});
it('falls back to the raw kind when no verb is mapped', async () => {
render(DashboardActivityFeed, {
props: {
feed: [baseItem({ kind: 'UNKNOWN_KIND' as unknown as ActivityFeedItemDTO['kind'] })]
}
});
expect(document.body.textContent).toContain('UNKNOWN_KIND');
});
it('renders a rollup time range when happenedAtUntil is set and count > 1', async () => {
render(DashboardActivityFeed, {
props: {
feed: [
baseItem({
happenedAt: '2026-04-14T14:02:00Z',
happenedAtUntil: '2026-04-14T14:32:00Z',
count: 3
})
]
}
});
// "14:0214:32" appears (with the en-dash)
expect(document.body.textContent).toMatch(/\d{2}:\d{2}\d{2}:\d{2}/);
});
it('uses the actor initials as the fallback name when name is null', async () => {
render(DashboardActivityFeed, {
props: {
feed: [
baseItem({
actor: {
id: 'u-2',
name: null as unknown as undefined,
initials: 'XR',
color: '#000'
}
})
]
}
});
const strong = document.querySelector('strong');
expect(strong?.textContent).toBe('XR');
});
it('builds the document detail href from documentId', async () => {
render(DashboardActivityFeed, {
props: { feed: [baseItem({ documentId: 'doc-xyz', documentTitle: 'Brief 1901' })] }
});
const link = document.querySelector('a[href="/documents/doc-xyz"]');
expect(link).not.toBeNull();
});
});