import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' import { http, HttpResponse } from 'msw' import { setupServer } from 'msw/node' import React from 'react' import { useStats } from '@/hooks/useStats' import type { UsageStats, StatsQueryParams } from '@/types' // Test data const mockStats: UsageStats[] = [ { id: 1, providerId: 'provider-1', modelName: 'gpt-4o', requestCount: 100, date: '2026-04-01', }, { id: 2, providerId: 'provider-1', modelName: 'gpt-4o-mini', requestCount: 50, date: '2026-04-01', }, ] const mockFilteredStats: UsageStats[] = [ { id: 3, providerId: 'provider-2', modelName: 'claude-sonnet-4-5', requestCount: 200, date: '2026-04-01', }, ] // Track the request URL for assertions let capturedUrl: URL | null = null // MSW handlers const handlers = [ http.get('/api/stats', ({ request }) => { capturedUrl = new URL(request.url) const providerId = capturedUrl.searchParams.get('provider_id') if (providerId === 'provider-2') { return HttpResponse.json(mockFilteredStats) } return HttpResponse.json(mockStats) }), ] const server = setupServer(...handlers) function createTestQueryClient() { return new QueryClient({ defaultOptions: { queries: { retry: false }, mutations: { retry: false }, }, }) } function createWrapper() { const testQueryClient = createTestQueryClient() return function Wrapper({ children }: { children: React.ReactNode }) { return {children} } } beforeAll(() => server.listen()) afterEach(() => { server.resetHandlers() capturedUrl = null }) afterAll(() => server.close()) describe('useStats', () => { it('fetches stats without params', async () => { const { result } = renderHook(() => useStats(), { wrapper: createWrapper(), }) await waitFor(() => expect(result.current.isSuccess).toBe(true)) expect(result.current.data).toEqual(mockStats) expect(result.current.data).toHaveLength(2) expect(result.current.data![0]!.modelName).toBe('gpt-4o') expect(result.current.data![1]!.requestCount).toBe(50) // Verify no query params were sent expect(capturedUrl!.search).toBe('') }) it('with filter params passes them correctly', async () => { const params: StatsQueryParams = { providerId: 'provider-2', modelName: 'claude-sonnet-4-5', startDate: '2026-04-01', endDate: '2026-04-15', } const { result } = renderHook(() => useStats(params), { wrapper: createWrapper(), }) await waitFor(() => expect(result.current.isSuccess).toBe(true)) expect(result.current.data).toEqual(mockFilteredStats) expect(result.current.data).toHaveLength(1) expect(result.current.data![0]!.modelName).toBe('claude-sonnet-4-5') // Verify query params were passed correctly (snake_case) expect(capturedUrl!.searchParams.get('provider_id')).toBe('provider-2') expect(capturedUrl!.searchParams.get('model_name')).toBe('claude-sonnet-4-5') expect(capturedUrl!.searchParams.get('start_date')).toBe('2026-04-01') expect(capturedUrl!.searchParams.get('end_date')).toBe('2026-04-15') }) it('with partial filter params only sends provided params', async () => { const params: StatsQueryParams = { providerId: 'provider-1', } const { result } = renderHook(() => useStats(params), { wrapper: createWrapper(), }) await waitFor(() => expect(result.current.isSuccess).toBe(true)) // Verify only provider_id was sent expect(capturedUrl!.searchParams.get('provider_id')).toBe('provider-1') expect(capturedUrl!.searchParams.get('model_name')).toBeNull() expect(capturedUrl!.searchParams.get('start_date')).toBeNull() expect(capturedUrl!.searchParams.get('end_date')).toBeNull() }) })