import { QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor, act } from '@testing-library/react' import { createTestQueryClient } from '../test/utils' import { usePokemonList, useCreateGame, useUpdateGame, useDeleteGame } from './useAdmin' vi.mock('../api/admin') vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn() } })) import * as adminApi from '../api/admin' import { toast } from 'sonner' function createWrapper() { const queryClient = createTestQueryClient() const wrapper = ({ children }: { children: React.ReactNode }) => ( {children} ) return { queryClient, wrapper } } describe('usePokemonList', () => { it('calls listPokemon with defaults', async () => { vi.mocked(adminApi.listPokemon).mockResolvedValue({ results: [], total: 0 } as never) const { wrapper } = createWrapper() const { result } = renderHook(() => usePokemonList(), { wrapper }) await waitFor(() => expect(result.current.isSuccess).toBe(true)) expect(adminApi.listPokemon).toHaveBeenCalledWith(undefined, 50, 0, undefined) }) it('passes search and filter params to listPokemon', async () => { vi.mocked(adminApi.listPokemon).mockResolvedValue({ results: [], total: 0 } as never) const { wrapper } = createWrapper() renderHook(() => usePokemonList('pika', 10, 20, 'electric'), { wrapper }) await waitFor(() => expect(adminApi.listPokemon).toHaveBeenCalledWith('pika', 10, 20, 'electric') ) }) }) describe('useCreateGame', () => { it('calls createGame with the provided input', async () => { vi.mocked(adminApi.createGame).mockResolvedValue({ id: 1 } as never) const { wrapper } = createWrapper() const { result } = renderHook(() => useCreateGame(), { wrapper }) const input = { name: 'FireRed', slug: 'firered', generation: 3, region: 'kanto', vgId: 1 } await act(async () => { await result.current.mutateAsync(input as never) }) expect(adminApi.createGame).toHaveBeenCalledWith(input) }) it('invalidates the games query on success', async () => { vi.mocked(adminApi.createGame).mockResolvedValue({} as never) const { queryClient, wrapper } = createWrapper() const spy = vi.spyOn(queryClient, 'invalidateQueries') const { result } = renderHook(() => useCreateGame(), { wrapper }) await act(async () => { await result.current.mutateAsync({} as never) }) expect(spy).toHaveBeenCalledWith({ queryKey: ['games'] }) }) it('shows a success toast after creating a game', async () => { vi.mocked(adminApi.createGame).mockResolvedValue({} as never) const { wrapper } = createWrapper() const { result } = renderHook(() => useCreateGame(), { wrapper }) await act(async () => { await result.current.mutateAsync({} as never) }) expect(toast.success).toHaveBeenCalledWith('Game created') }) it('shows an error toast on failure', async () => { vi.mocked(adminApi.createGame).mockRejectedValue(new Error('Conflict')) const { wrapper } = createWrapper() const { result } = renderHook(() => useCreateGame(), { wrapper }) await act(async () => { result.current.mutate({} as never) }) await waitFor(() => expect(toast.error).toHaveBeenCalledWith('Failed to create game: Conflict')) }) }) describe('useUpdateGame', () => { it('calls updateGame with id and data', async () => { vi.mocked(adminApi.updateGame).mockResolvedValue({} as never) const { wrapper } = createWrapper() const { result } = renderHook(() => useUpdateGame(), { wrapper }) await act(async () => { await result.current.mutateAsync({ id: 7, data: { name: 'Renamed' } } as never) }) expect(adminApi.updateGame).toHaveBeenCalledWith(7, { name: 'Renamed' }) }) it('invalidates games and shows a toast on success', async () => { vi.mocked(adminApi.updateGame).mockResolvedValue({} as never) const { queryClient, wrapper } = createWrapper() const spy = vi.spyOn(queryClient, 'invalidateQueries') const { result } = renderHook(() => useUpdateGame(), { wrapper }) await act(async () => { await result.current.mutateAsync({ id: 1, data: {} } as never) }) expect(spy).toHaveBeenCalledWith({ queryKey: ['games'] }) expect(toast.success).toHaveBeenCalledWith('Game updated') }) }) describe('useDeleteGame', () => { it('calls deleteGame with the given id', async () => { vi.mocked(adminApi.deleteGame).mockResolvedValue(undefined as never) const { wrapper } = createWrapper() const { result } = renderHook(() => useDeleteGame(), { wrapper }) await act(async () => { await result.current.mutateAsync(3) }) expect(adminApi.deleteGame).toHaveBeenCalledWith(3) }) it('invalidates games and shows a toast on success', async () => { vi.mocked(adminApi.deleteGame).mockResolvedValue(undefined as never) const { queryClient, wrapper } = createWrapper() const spy = vi.spyOn(queryClient, 'invalidateQueries') const { result } = renderHook(() => useDeleteGame(), { wrapper }) await act(async () => { await result.current.mutateAsync(3) }) expect(spy).toHaveBeenCalledWith({ queryKey: ['games'] }) expect(toast.success).toHaveBeenCalledWith('Game deleted') }) })