Files
familienarchiv/frontend/src/lib/activity/ChronikTimeline.svelte.spec.ts
2026-05-05 13:47:09 +02:00

100 lines
3.3 KiB
TypeScript

import { describe, it, expect, afterEach } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { page } from 'vitest/browser';
import ChronikTimeline from './ChronikTimeline.svelte';
import type { components } from '$lib/generated/api';
type ActivityFeedItemDTO = components['schemas']['ActivityFeedItemDTO'];
afterEach(cleanup);
function item(partial: Partial<ActivityFeedItemDTO>): ActivityFeedItemDTO {
return {
kind: 'TEXT_SAVED',
actor: { initials: 'AB', color: '#123456', name: 'Anna Beta' },
documentId: 'doc-x',
documentTitle: 'Some document',
happenedAt: new Date().toISOString(),
youMentioned: false,
count: 1,
...partial
};
}
function atOffsetDays(days: number): string {
const d = new Date();
d.setDate(d.getDate() - days);
return d.toISOString();
}
describe('ChronikTimeline', () => {
it('renders nothing / no bucket headers when items is empty', async () => {
render(ChronikTimeline, { items: [] });
expect(document.querySelector('[data-testid="chronik-bucket-today"]')).toBeNull();
expect(document.querySelector('[data-testid="chronik-bucket-yesterday"]')).toBeNull();
expect(document.querySelector('[data-testid="chronik-bucket-thisWeek"]')).toBeNull();
expect(document.querySelector('[data-testid="chronik-bucket-older"]')).toBeNull();
});
it('places today items in the today bucket with a "Heute" header', async () => {
render(ChronikTimeline, {
items: [
item({
documentId: 'doc-today',
documentTitle: 'Frisches Dokument',
happenedAt: new Date().toISOString()
})
]
});
const today = document.querySelector('[data-testid="chronik-bucket-today"]');
expect(today).not.toBeNull();
await expect.element(page.getByText('Heute', { exact: true })).toBeInTheDocument();
// The row for the today item should be inside the today bucket.
expect(today?.textContent).toContain('Frisches Dokument');
});
it('does not render an empty bucket header when no items fall into it', async () => {
render(ChronikTimeline, {
items: [item({ happenedAt: new Date().toISOString() })]
});
// Only today bucket should exist.
expect(document.querySelector('[data-testid="chronik-bucket-today"]')).not.toBeNull();
expect(document.querySelector('[data-testid="chronik-bucket-older"]')).toBeNull();
});
it('places older items in the older bucket', async () => {
render(ChronikTimeline, {
items: [
item({
documentId: 'doc-old',
documentTitle: 'Alt Doc',
happenedAt: atOffsetDays(30)
})
]
});
const older = document.querySelector('[data-testid="chronik-bucket-older"]');
expect(older).not.toBeNull();
expect(older?.textContent).toContain('Alt Doc');
});
it('groups multiple items into their respective buckets', async () => {
render(ChronikTimeline, {
items: [
item({
documentId: 'd1',
documentTitle: 'Heute Item',
happenedAt: new Date().toISOString()
}),
item({ documentId: 'd2', documentTitle: 'Alt Item', happenedAt: atOffsetDays(30) })
]
});
const today = document.querySelector('[data-testid="chronik-bucket-today"]');
const older = document.querySelector('[data-testid="chronik-bucket-older"]');
expect(today?.textContent).toContain('Heute Item');
expect(today?.textContent).not.toContain('Alt Item');
expect(older?.textContent).toContain('Alt Item');
expect(older?.textContent).not.toContain('Heute Item');
});
});