원문 보기 : https://tkdodo.eu/blog/testing-react-query
Testing React Query
Let's take a look at how to efficiently test custom useQuery hooks and components using them.
tkdodo.eu
순수하지 않은 컴포넌트
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 |