import { describe, it, expect, vi, beforeEach } from 'vitest'; import { renderHook, waitFor, act } from '@testing-library/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import React from 'react'; // Mock the notifications API vi.mock('../../api/notifications', () => ({ getNotifications: vi.fn(), getUnreadCount: vi.fn(), markNotificationRead: vi.fn(), markAllNotificationsRead: vi.fn(), clearAllNotifications: vi.fn(), })); import { useNotifications, useUnreadNotificationCount, useMarkNotificationRead, useMarkAllNotificationsRead, useClearAllNotifications, } from '../useNotifications'; import * as notificationsApi from '../../api/notifications'; // Create wrapper const createWrapper = () => { const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false }, mutations: { retry: false }, }, }); return function Wrapper({ children }: { children: React.ReactNode }) { return React.createElement(QueryClientProvider, { client: queryClient }, children); }; }; describe('useNotifications hooks', () => { beforeEach(() => { vi.clearAllMocks(); }); describe('useNotifications', () => { it('fetches notifications', async () => { const mockNotifications = [ { id: 1, verb: 'created', read: false, timestamp: '2024-01-01T00:00:00Z' }, ]; vi.mocked(notificationsApi.getNotifications).mockResolvedValue(mockNotifications); const { result } = renderHook(() => useNotifications(), { wrapper: createWrapper(), }); await waitFor(() => { expect(result.current.isSuccess).toBe(true); }); expect(notificationsApi.getNotifications).toHaveBeenCalledWith(undefined); expect(result.current.data).toEqual(mockNotifications); }); it('passes options to API', async () => { vi.mocked(notificationsApi.getNotifications).mockResolvedValue([]); renderHook(() => useNotifications({ read: false, limit: 10 }), { wrapper: createWrapper(), }); await waitFor(() => { expect(notificationsApi.getNotifications).toHaveBeenCalledWith({ read: false, limit: 10, }); }); }); }); describe('useUnreadNotificationCount', () => { it('fetches unread count', async () => { vi.mocked(notificationsApi.getUnreadCount).mockResolvedValue(5); const { result } = renderHook(() => useUnreadNotificationCount(), { wrapper: createWrapper(), }); await waitFor(() => { expect(result.current.isSuccess).toBe(true); }); expect(result.current.data).toBe(5); }); }); describe('useMarkNotificationRead', () => { it('marks notification as read', async () => { vi.mocked(notificationsApi.markNotificationRead).mockResolvedValue(undefined); const { result } = renderHook(() => useMarkNotificationRead(), { wrapper: createWrapper(), }); await act(async () => { await result.current.mutateAsync(42); }); expect(notificationsApi.markNotificationRead).toHaveBeenCalled(); expect(vi.mocked(notificationsApi.markNotificationRead).mock.calls[0][0]).toBe(42); }); }); describe('useMarkAllNotificationsRead', () => { it('marks all notifications as read', async () => { vi.mocked(notificationsApi.markAllNotificationsRead).mockResolvedValue(undefined); const { result } = renderHook(() => useMarkAllNotificationsRead(), { wrapper: createWrapper(), }); await act(async () => { await result.current.mutateAsync(); }); expect(notificationsApi.markAllNotificationsRead).toHaveBeenCalled(); }); }); describe('useClearAllNotifications', () => { it('clears all notifications', async () => { vi.mocked(notificationsApi.clearAllNotifications).mockResolvedValue(undefined); const { result } = renderHook(() => useClearAllNotifications(), { wrapper: createWrapper(), }); await act(async () => { await result.current.mutateAsync(); }); expect(notificationsApi.clearAllNotifications).toHaveBeenCalled(); }); }); });