import { describe, it, expect, vi, afterEach } from 'vitest'; import { cleanup, render } from 'vitest-browser-svelte'; import { page } from 'vitest/browser'; import ChronikFuerDichBox from './ChronikFuerDichBox.svelte'; import type { NotificationItem } from '$lib/notification/notifications'; vi.mock('$app/forms', () => ({ enhance(node: HTMLFormElement, submit?: (opts: { formData: FormData }) => unknown) { const handler = (e: Event) => { e.preventDefault(); submit?.({ formData: new FormData(node) } as never); }; node.addEventListener('submit', handler); return { destroy: () => node.removeEventListener('submit', handler) }; } })); afterEach(cleanup); const mention = (overrides: Partial = {}): NotificationItem => ({ id: 'n-1', type: 'MENTION', documentId: 'doc-1', referenceId: 'ref-1', annotationId: null, read: false, createdAt: new Date().toISOString(), actorName: 'Anna', documentTitle: 'Brief 1899', ...overrides }); describe('ChronikFuerDichBox', () => { it('renders the inbox-zero state when there are no unread', async () => { render(ChronikFuerDichBox, { props: { unread: [], optimisticMarkRead: () => {}, optimisticMarkAllRead: () => {} } }); await expect.element(page.getByText(/keine neuen erwähnungen/i)).toBeVisible(); const link = document.querySelector('a[href="/aktivitaeten?filter=fuer-dich"]'); expect(link).not.toBeNull(); }); it('renders the count badge with the unread count', async () => { render(ChronikFuerDichBox, { props: { unread: [mention(), mention({ id: 'n-2' }), mention({ id: 'n-3' })], optimisticMarkRead: () => {}, optimisticMarkAllRead: () => {} } }); const badge = document.querySelector('[data-testid="chronik-fuerdich-count"]'); expect(badge?.textContent).toContain('3'); }); it('uses the @ glyph for MENTION and ↩ for REPLY', async () => { render(ChronikFuerDichBox, { props: { unread: [mention({ id: 'n-m', type: 'MENTION' }), mention({ id: 'n-r', type: 'REPLY' })], optimisticMarkRead: () => {}, optimisticMarkAllRead: () => {} } }); const items = document.querySelectorAll('ul[role="list"] li'); expect(items.length).toBe(2); expect(items[0].textContent).toContain('@'); expect(items[1].textContent).toContain('↩'); }); it('renders MENTION verb text from paraglide messages', async () => { render(ChronikFuerDichBox, { props: { unread: [mention({ actorName: 'Bertha' })], optimisticMarkRead: () => {}, optimisticMarkAllRead: () => {} } }); await expect .element(page.getByText(/bertha hat dich in einem kommentar erwähnt/i)) .toBeVisible(); }); it('renders REPLY verb text from paraglide messages', async () => { render(ChronikFuerDichBox, { props: { unread: [mention({ type: 'REPLY', actorName: 'Carl' })], optimisticMarkRead: () => {}, optimisticMarkAllRead: () => {} } }); await expect .element(page.getByText(/carl hat auf deinen kommentar geantwortet/i)) .toBeVisible(); }); it('calls optimisticMarkRead with the notification id when its dismiss button is clicked', async () => { const optimisticMarkRead = vi.fn(); const item = mention({ id: 'n-7' }); render(ChronikFuerDichBox, { props: { unread: [item], optimisticMarkRead, optimisticMarkAllRead: () => {} } }); const dismiss = document.querySelector( '[data-testid="chronik-fuerdich-dismiss"]' ) as HTMLElement; dismiss.click(); expect(optimisticMarkRead).toHaveBeenCalledWith('n-7'); }); it('calls optimisticMarkAllRead when the mark-all-read button is clicked', async () => { const optimisticMarkAllRead = vi.fn(); render(ChronikFuerDichBox, { props: { unread: [mention()], optimisticMarkRead: () => {}, optimisticMarkAllRead } }); const btn = document.querySelector('[data-testid="chronik-mark-all-read"]') as HTMLElement; btn.click(); expect(optimisticMarkAllRead).toHaveBeenCalledOnce(); }); it('builds a deep-link href to the comment for each notification', async () => { render(ChronikFuerDichBox, { props: { unread: [mention({ documentId: 'doc-x', referenceId: 'ref-y', annotationId: null })], optimisticMarkRead: () => {}, optimisticMarkAllRead: () => {} } }); const link = document.querySelector('ul[role="list"] li a') as HTMLAnchorElement; expect(link.getAttribute('href')).toContain('doc-x'); }); });