React Query-テスト編
TanStack | High Quality Open-Source Software for Web Developers
React Query について公式ドキュメントを読みながら自分に必要なものをまとめたメモを記事化したもので以下の 4 つの記事で構成されています。記事ができたものから順次リンク化していきます。
- React Query-基礎知識編
- React Query-データ取得編
- React Query-データ更新編
- React Query-テスト編
参考記事
Testing | TanStack Query Docs
API | Testing Library
MSW – Seamless API mocking library for browser and Node | Mock Service Worker
Testing React Query | TkDodo's blog
ReactQueryを用いたhooksのテストを書きたい
react-query : useQuery への依存をスタブに差し替えてコンポーネントテスト
準備
render や renderHook が使えるようにパッケージ追加
npm install @testing-library/react @testing-library/react-hooks react-test-renderer --save-dev
ネットワークアクセスに関しては MSW を使うと本来の動きをシミューレートできる
npm install msw --save-dev
Wrapper
基本的にはテスト対象を以下のように QueryClientProvider の中に配置する
const queryClient = new QueryClient()
render(
<QueryClientProvider client={queryClient}>
<TestComponent />
</QueryClientProvider>
)
hooks のテストに使う renderHook は options の wrapper を使う必要がある
ちなみにこの wrapper は render にも同じ方法で使える
const queryClient = new QueryClient()
const queryWrapper = ({children}:QueryWrapperProps) => {
return (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
)
}
const {result} = renderHook(() => useHooks(), { wrapper: queryWrapper })
QueryClient を使いたい場合も多いので以下のような create 関数を用意すると便利。 ついでに retry なし & 自動再取得なしにしている。
import { ReactElement } from 'react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
export const createQueryWrapper = () => {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
staleTime: Infinity
}
}
})
const queryWrapper = ({children}: {children: ReactElement}) => {
return (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
)
}
return { queryClient, queryWrapper }
}
使い方
import { createQueryWrapper } from './testWrapper'
// queryClient が不要なら受け取らない
const { queryWrapper } = createQueryWrapper()
render(<TestComponent />, { wraper: queryWrapper })
renderHook(() => useHooks, { wraper: queryWrapper })
Tips
QueryClient を使ってキャッシュを登録し API アクセス不要にする
const { queryClient, queryWrapper } = createQueryWrapper()
queryClient.setQueryData(['users'], {
[{
id: 'test_id_1',
name: 'test_name_1',
age: 20,
}]
})
render(<TestComponent />, {wrapper: queryWrapper})
コンポーネントを描画する関数を提供する hooks の場合は render 側で使う
const { result } = renderHook(() => useComponent())
render(result.current(), { wrapper: queryWrapper})
データの取得待ち
const {result} = renderHook(() => useUsers(), {wrapper: queryWrapper})
// 変数の場合
await waitFor(() => !!result.current.users)
// 要素の場合(find系を使う)
const target = await screen.findByText('username')
Discussion