원문 보기 : https://tkdodo.eu/blog/testing-react-query
순수하지 않은 컴포넌트
useContext, useSelector, useQuery를 사용하는 컴포넌트들은 순수하지 않습니다.
다른 환경에서 호출하면 다른 결과가 발생하기 때문입니다.
해당 컴포넌트들을 테스트 할 때에는 "의존성" 공급에 대해 생각해야 합니다.
네트워크 요청 흉내내기
React Query는 비동기 서버 상태 관리 라이브러리이므로
Kent C. Dodds가 Stop mocking fetch 기사에서 쓴 것을 다시 한 번 말합니다.
Use mock service worker by @ApiMocking
- 테스트 시 node 환경에서 동작합니다.
- REST, GraphQL 모두 지원합니다.
- storybook addon이 있으므로 useQuery를 사용하는 컴포넌트의 스토리를 작성할 수 있습니다.
- 개발 환경의 브라우저에서 동작합니다. 즉, 브라우저 개발 도구의 네트워크 탭에서 요청을 볼 수 있습니다.
- fixture(테스트 환경 설정 객체)와 함깨, cypress와 함께 동작합니다.
QueryClientProvider
React Query를 사용할 때 QueryClientProvider가 필요하고,
QueryCache를 보유하는 껍데기인 queryClient를 제공해야 합니다. 캐시는 쿼리 각각의 데이터를 보유합니다.
각 테스트에 고유한 QueryClientProvider를 제공하고 각 테스트에 대해 새 QueryClient를 만드는 것을 선호합니다.
그렇게 하면 테스트가 서로 완전히 격리됩니다.
커스텀 훅 테스트
커스텀 hook 테스트 시, react-hooks-testing-library를 사용하면 hook을 테스트하기 쉽습니다.
컨텍스트 내에서 커스텀 훅이 호출되는지 여부 확인
const createWrapper = () => {
// ✅ creates a new QueryClient for each test
const queryClient = new QueryClient()
return ({ children }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
)
}
test("my first test", async () => {
const { result } = renderHook(() => useCustomHook(), {
wrapper: createWrapper()
})
}
컴포넌트 테스트
재시도 설정 끄기
const createWrapper = () => {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
// ✅ turns retries off
retry: false,
},
},
})
return ({ children }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
)
}
test("my first test", async () => {
const { result } = renderHook(() => useCustomHook(), {
wrapper: createWrapper()
})
}
setQueryDefaults
🚨 useQuery에서 테스트 옵션을 직접 설정하지 마세요
const queryClient = new QueryClient()
function App() {
return (
<QueryClientProvider client={queryClient}>
<Example />
</QueryClientProvider>
)
}
function Example() {
// 🚨 you cannot override this setting for tests!
const queryInfo = useQuery('todos', fetchTodos, { retry: 5 })
}
✅ 이렇게 하세요
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: 2,
},
},
})
// ✅ only todos will retry 5 times
queryClient.setQueryDefaults('todos', { retry: 5 })
function App() {
return (
<QueryClientProvider client={queryClient}>
<Example />
</QueryClientProvider>
)
}
모든 쿼리는 2번 재시도하고 todos만 5번 재시도하며,
테스트의 모든 쿼리에 대해 이 기능을 끌 수 있습니다🙌.
ReactQueryConfigProvider
const ReactQueryConfigProvider = ({ children, defaultOptions }) => {
const client = useQueryClient()
const [newClient] = React.useState(
() =>
new QueryClient({
queryCache: client.getQueryCache(),
muationCache: client.getMutationCache(),
defaultOptions,
})
)
return (
<QueryClientProvider client={newClient}>{children}</QueryClientProvider>
)
}
항상 쿼리 응답 기다리기
const createWrapper = () => {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
})
return ({ children }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
)
}
test("my first test", async () => {
const { result, waitFor } = renderHook(() => useCustomHook(), {
wrapper: createWrapper()
})
// ✅ wait until the query has transitioned to success state
await waitFor(() => result.current.isSuccess)
expect(result.current.data).toBeDefined()
}
@testing-library/react v13.1.0에는 renderHook도 있습니다. (리액트-훅-테스트-라이브러리 대신 사용 가능한 듯...)
그러나 자체적으로 waitFor 유틸리티를 반환하지 않으므로 @testing-library/react에서 가져올 수 있는 유틸리티를 대신 사용해야 합니다.
API는 부울 값 대신 promise를 반환하는 것을 기대하기에, 코드를 약간 수정합니다.
import { waitFor, renderHook } from '@testing-library/react'
test("my first test", async () => {
const { result } = renderHook(() => useCustomHook(), {
wrapper: createWrapper()
})
// ✅ return a Promise via expect to waitFor
await waitFor(() => expect(result.current.isSuccess).toBe(true))
expect(result.current.data).toBeDefined()
}
에러 콘솔 끄기
const queryClient = new QueryClient({
logger: {
log: console.log,
warn: console.warn,
// ✅ no more errors on the console
error: () => {},
}
})
정리하며
msw와 react-testing-library를 이용해 구현한,
커스텀 훅 및 컴포넌트에 대한 실패 및 성공 네 가지 테스트 케이스를 살펴보세요.
'FrontEnd' 카테고리의 다른 글
리액트 쿼리 : 웹소켓 (0) | 2022.06.18 |
---|---|
리액트 쿼리 : 타입스크립트 (0) | 2022.06.18 |
리액트 쿼리 : 쿼리 상태 체크 (0) | 2022.06.18 |
리액트 쿼리 : 렌더링 최적화 (0) | 2022.06.17 |
리액트 쿼리 : 서버 응답 변환 위치 (0) | 2022.06.17 |