// src/hooks/queries/useActivityLogQuery.test.tsx import { renderHook, waitFor } from '@testing-library/react'; import { describe, it, expect, vi, beforeEach } from 'vitest'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import type { ReactNode } from 'react'; import { useActivityLogQuery } from './useActivityLogQuery'; import * as apiClient from '../../services/apiClient'; vi.mock('../../services/apiClient'); const mockedApiClient = vi.mocked(apiClient); describe('useActivityLogQuery', () => { let queryClient: QueryClient; const wrapper = ({ children }: { children: ReactNode }) => ( {children} ); beforeEach(() => { vi.resetAllMocks(); queryClient = new QueryClient({ defaultOptions: { queries: { retry: false }, }, }); }); it('should fetch activity log with default params', async () => { const mockActivityLog = [ { id: 1, action: 'user_login', timestamp: '2024-01-01T10:00:00Z' }, { id: 2, action: 'flyer_uploaded', timestamp: '2024-01-01T11:00:00Z' }, ]; mockedApiClient.fetchActivityLog.mockResolvedValue({ ok: true, json: () => Promise.resolve(mockActivityLog), } as Response); const { result } = renderHook(() => useActivityLogQuery(), { wrapper }); await waitFor(() => expect(result.current.isSuccess).toBe(true)); expect(mockedApiClient.fetchActivityLog).toHaveBeenCalledWith(20, 0); expect(result.current.data).toEqual(mockActivityLog); }); it('should fetch activity log with custom limit and offset', async () => { const mockActivityLog = [{ id: 3, action: 'item_added', timestamp: '2024-01-01T12:00:00Z' }]; mockedApiClient.fetchActivityLog.mockResolvedValue({ ok: true, json: () => Promise.resolve(mockActivityLog), } as Response); const { result } = renderHook(() => useActivityLogQuery(10, 5), { wrapper }); await waitFor(() => expect(result.current.isSuccess).toBe(true)); expect(mockedApiClient.fetchActivityLog).toHaveBeenCalledWith(10, 5); expect(result.current.data).toEqual(mockActivityLog); }); it('should handle API error with error message', async () => { mockedApiClient.fetchActivityLog.mockResolvedValue({ ok: false, status: 403, json: () => Promise.resolve({ message: 'Admin access required' }), } as Response); const { result } = renderHook(() => useActivityLogQuery(), { wrapper }); await waitFor(() => expect(result.current.isError).toBe(true)); expect(result.current.error?.message).toBe('Admin access required'); }); it('should handle API error without message', async () => { mockedApiClient.fetchActivityLog.mockResolvedValue({ ok: false, status: 500, json: () => Promise.reject(new Error('Parse error')), } as Response); const { result } = renderHook(() => useActivityLogQuery(), { wrapper }); await waitFor(() => expect(result.current.isError).toBe(true)); expect(result.current.error?.message).toBe('Request failed with status 500'); }); it('should use fallback message when error.message is empty', async () => { mockedApiClient.fetchActivityLog.mockResolvedValue({ ok: false, status: 500, json: () => Promise.resolve({ message: '' }), } as Response); const { result } = renderHook(() => useActivityLogQuery(), { wrapper }); await waitFor(() => expect(result.current.isError).toBe(true)); expect(result.current.error?.message).toBe('Failed to fetch activity log'); }); it('should return empty array for no activity log entries', async () => { mockedApiClient.fetchActivityLog.mockResolvedValue({ ok: true, json: () => Promise.resolve([]), } as Response); const { result } = renderHook(() => useActivityLogQuery(), { wrapper }); await waitFor(() => expect(result.current.isSuccess).toBe(true)); expect(result.current.data).toEqual([]); }); });