Files
nuzlocke-tracker/frontend/src/hooks/useGames.test.tsx
Julian Tabel 0d2f419c6a Add unit tests for frontend utilities and hooks
82 tests covering download.ts and all React Query hooks. API modules are
mocked with vi.mock; mutation tests spy on queryClient.invalidateQueries
to verify cache invalidation. Conditional queries (null id) are verified
to stay idle.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 13:47:55 +01:00

90 lines
3.1 KiB
TypeScript

import { QueryClientProvider } from '@tanstack/react-query'
import { renderHook, waitFor } from '@testing-library/react'
import { createTestQueryClient } from '../test/utils'
import { useGames, useGame, useGameRoutes, useRoutePokemon } from './useGames'
vi.mock('../api/games')
import { getGames, getGame, getGameRoutes, getRoutePokemon } from '../api/games'
function createWrapper() {
const queryClient = createTestQueryClient()
const wrapper = ({ children }: { children: React.ReactNode }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
)
return { queryClient, wrapper }
}
describe('useGames', () => {
it('calls getGames and returns data', async () => {
const games = [{ id: 1, name: 'Red' }]
vi.mocked(getGames).mockResolvedValue(games as never)
const { wrapper } = createWrapper()
const { result } = renderHook(() => useGames(), { wrapper })
await waitFor(() => expect(result.current.isSuccess).toBe(true))
expect(getGames).toHaveBeenCalledOnce()
expect(result.current.data).toEqual(games)
})
})
describe('useGame', () => {
it('calls getGame with the given id', async () => {
const game = { id: 2, name: 'Blue' }
vi.mocked(getGame).mockResolvedValue(game as never)
const { wrapper } = createWrapper()
const { result } = renderHook(() => useGame(2), { wrapper })
await waitFor(() => expect(result.current.isSuccess).toBe(true))
expect(getGame).toHaveBeenCalledWith(2)
})
})
describe('useGameRoutes', () => {
it('is disabled when gameId is null', () => {
const { wrapper } = createWrapper()
const { result } = renderHook(() => useGameRoutes(null), { wrapper })
expect(result.current.fetchStatus).toBe('idle')
expect(getGameRoutes).not.toHaveBeenCalled()
})
it('fetches routes when gameId is provided', async () => {
const routes = [{ id: 10, name: 'Route 1' }]
vi.mocked(getGameRoutes).mockResolvedValue(routes as never)
const { wrapper } = createWrapper()
const { result } = renderHook(() => useGameRoutes(1), { wrapper })
await waitFor(() => expect(result.current.isSuccess).toBe(true))
expect(getGameRoutes).toHaveBeenCalledWith(1, undefined)
expect(result.current.data).toEqual(routes)
})
it('passes allowedTypes to the API', async () => {
vi.mocked(getGameRoutes).mockResolvedValue([] as never)
const { wrapper } = createWrapper()
renderHook(() => useGameRoutes(5, ['grass', 'water']), { wrapper })
await waitFor(() => expect(getGameRoutes).toHaveBeenCalledWith(5, ['grass', 'water']))
})
})
describe('useRoutePokemon', () => {
it('is disabled when routeId is null', () => {
const { wrapper } = createWrapper()
const { result } = renderHook(() => useRoutePokemon(null), { wrapper })
expect(result.current.fetchStatus).toBe('idle')
expect(getRoutePokemon).not.toHaveBeenCalled()
})
it('fetches pokemon for a given route', async () => {
vi.mocked(getRoutePokemon).mockResolvedValue([] as never)
const { wrapper } = createWrapper()
renderHook(() => useRoutePokemon(3, 1), { wrapper })
await waitFor(() => expect(getRoutePokemon).toHaveBeenCalledWith(3, 1))
})
})