83 lines
2.5 KiB
TypeScript
83 lines
2.5 KiB
TypeScript
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> = {}): 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<HTMLButtonElement>('button[aria-haspopup="true"]')!;
|
|
bellButton.click();
|
|
await vi.waitFor(() => {
|
|
expect(document.querySelector('[role="dialog"]')).not.toBeNull();
|
|
});
|
|
const notifButton = document.querySelector<HTMLButtonElement>('[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');
|
|
});
|
|
});
|
|
});
|