Files
nuzlocke-tracker/frontend/src/hooks/usePokemon.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

94 lines
3.2 KiB
TypeScript

import { QueryClientProvider } from '@tanstack/react-query'
import { renderHook, waitFor } from '@testing-library/react'
import { createTestQueryClient } from '../test/utils'
import {
usePokemon,
usePokemonFamilies,
usePokemonEncounterLocations,
usePokemonEvolutionChain,
} from './usePokemon'
vi.mock('../api/pokemon')
import {
getPokemon,
fetchPokemonFamilies,
fetchPokemonEncounterLocations,
fetchPokemonEvolutionChain,
} from '../api/pokemon'
function createWrapper() {
const queryClient = createTestQueryClient()
const wrapper = ({ children }: { children: React.ReactNode }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
)
return { queryClient, wrapper }
}
describe('usePokemon', () => {
it('is disabled when id is null', () => {
const { wrapper } = createWrapper()
const { result } = renderHook(() => usePokemon(null), { wrapper })
expect(result.current.fetchStatus).toBe('idle')
expect(getPokemon).not.toHaveBeenCalled()
})
it('fetches a pokemon by id', async () => {
const mon = { id: 25, name: 'pikachu' }
vi.mocked(getPokemon).mockResolvedValue(mon as never)
const { wrapper } = createWrapper()
const { result } = renderHook(() => usePokemon(25), { wrapper })
await waitFor(() => expect(result.current.isSuccess).toBe(true))
expect(getPokemon).toHaveBeenCalledWith(25)
expect(result.current.data).toEqual(mon)
})
})
describe('usePokemonFamilies', () => {
it('calls fetchPokemonFamilies and returns data', async () => {
const families = [{ id: 1, members: [] }]
vi.mocked(fetchPokemonFamilies).mockResolvedValue(families as never)
const { wrapper } = createWrapper()
const { result } = renderHook(() => usePokemonFamilies(), { wrapper })
await waitFor(() => expect(result.current.isSuccess).toBe(true))
expect(fetchPokemonFamilies).toHaveBeenCalledOnce()
expect(result.current.data).toEqual(families)
})
})
describe('usePokemonEncounterLocations', () => {
it('is disabled when pokemonId is null', () => {
const { wrapper } = createWrapper()
const { result } = renderHook(() => usePokemonEncounterLocations(null), { wrapper })
expect(result.current.fetchStatus).toBe('idle')
})
it('fetches encounter locations for a given pokemon', async () => {
vi.mocked(fetchPokemonEncounterLocations).mockResolvedValue([] as never)
const { wrapper } = createWrapper()
renderHook(() => usePokemonEncounterLocations(25), { wrapper })
await waitFor(() => expect(fetchPokemonEncounterLocations).toHaveBeenCalledWith(25))
})
})
describe('usePokemonEvolutionChain', () => {
it('is disabled when pokemonId is null', () => {
const { wrapper } = createWrapper()
const { result } = renderHook(() => usePokemonEvolutionChain(null), { wrapper })
expect(result.current.fetchStatus).toBe('idle')
})
it('fetches the evolution chain for a given pokemon', async () => {
vi.mocked(fetchPokemonEvolutionChain).mockResolvedValue([] as never)
const { wrapper } = createWrapper()
renderHook(() => usePokemonEvolutionChain(4), { wrapper })
await waitFor(() => expect(fetchPokemonEvolutionChain).toHaveBeenCalledWith(4))
})
})