import { afterEach, describe, it, expect, vi } from 'vitest'; import { cleanup, render } from 'vitest-browser-svelte'; import type { NotificationItem } from '$lib/utils/notifications'; import NotificationBell from './NotificationBell.svelte'; const gotoMock = vi.hoisted(() => vi.fn()); vi.mock('$app/navigation', () => ({ goto: gotoMock, beforeNavigate: vi.fn() })); const mockMarkRead = vi.hoisted(() => vi.fn().mockResolvedValue(undefined)); const mockNotificationList = vi.hoisted((): { value: NotificationItem[] } => ({ value: [] })); vi.mock('$lib/stores/notifications.svelte', () => ({ notificationStore: { get notifications() { return mockNotificationList.value; }, get unreadCount() { return mockNotificationList.value.length; }, markRead: mockMarkRead, fetchNotifications: vi.fn().mockResolvedValue(undefined), init: vi.fn(), destroy: vi.fn(), markAllRead: vi.fn() } })); afterEach(() => { cleanup(); gotoMock.mockClear(); mockMarkRead.mockClear(); mockNotificationList.value = []; }); const makeNotification = (overrides: Partial = {}): NotificationItem => ({ id: 'n1', type: 'REPLY', documentId: 'doc-1', referenceId: 'ref-1', annotationId: null, read: false, createdAt: '2026-04-21T10:00:00Z', actorName: 'Anna', documentTitle: 'Test Doc', ...overrides }); async function openDropdownAndClickFirstNotification() { const bellButton = document.querySelector('button[aria-haspopup="true"]')!; bellButton.click(); await vi.waitFor(() => { expect(document.querySelector('[role="dialog"]')).not.toBeNull(); }); const notifButton = document.querySelector('[role="list"] button')!; notifButton.click(); } describe('NotificationBell', () => { it('handleMarkRead navigates to URL including annotationId when notification has annotationId', async () => { mockNotificationList.value = [makeNotification({ annotationId: 'annot-1' })]; render(NotificationBell); await openDropdownAndClickFirstNotification(); await vi.waitFor(() => { expect(gotoMock).toHaveBeenCalledWith( '/documents/doc-1?commentId=ref-1&annotationId=annot-1' ); }); }); it('handleMarkRead navigates to commentId-only URL when annotationId is absent', async () => { mockNotificationList.value = [makeNotification({ annotationId: null })]; render(NotificationBell); await openDropdownAndClickFirstNotification(); await vi.waitFor(() => { expect(gotoMock).toHaveBeenCalledWith('/documents/doc-1?commentId=ref-1'); }); }); });