react-query suspense mode 테스트 삽집 후기
May 24, 2022 - [react-query, suspense, test]
다음과 같이 suspense 모드를 사용하는 커스텀 훅이 있다고 해보자
import { useQuery } from 'react-query'
import { isNil } from '@madup-inc/utils'
import { BusinessApi } from 'api/index'
export default function useBusiness({ bizId }) {
return useQuery(
['business', bizId],
() => BusinessApi.getBusiness({ bizId }),
{
suspense: true,
enabled: !isNil(bizId),
},
)
}
그리고 테스트케이스를 아래와 같이 작성했다.
import useBusiness from 'queries/useBusiness'
import { BusinessApi } from 'api/index'
import { QueryClient, QueryClientProvider } from 'react-query'
import { renderHook } from '@testing-library/react-hooks'
import ErrorScreen from '../ui-component/ErrorScreen'
import ErrorBoundary from '../ErrorBoundary'
jest.mock('api/index')
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retryDelay: attemptIndex =>
Math.min(1000 * 2 ** attemptIndex, 30000),
retry: 0,
staleTime: 1000 * 10, // cached for 10 seconds
},
},
})
const wrapper = ({ children }) => (
<ErrorBoundary fallback={ErrorScreen}>
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
</ErrorBoundary>
)
describe('useBusiness', () => {
test('bizId 가 다를 경우에만 api 호출이 발생해야 한다.', async () => {
BusinessApi.getBusiness.mockResolvedValue('hello world')
const { waitFor, result, waitForNextUpdate } = renderHook(
() => useBusiness({ bizId: 1 }),
{ wrapper },
)
//
// await waitForNextUpdate({ timeout: 5000 })
await waitFor(() => result?.current?.data !== undefined, { timeout: 5000 })
expect(BusinessApi.getBusiness).toHaveBeenCalledTimes(1)
})
})
우선 undefined 에서 current 를 읽을 수 없다는 이상한 오류가 뜬다면 react 버젼과 react-test-renderer 의 버젼이 일치하는 지 확인하자.
필자는 둘의 버젼을 일치시킴으로 해당 문제는 해결을 하였다.
https://github.com/testing-library/react-hooks-testing-library/issues/753#issuecomment-1135441708
그리고 다음 오류를 만났다.
Watch Usage: Press w to show more.
FAIL src/queries/useBusiness.test.js (10.812 s)
useBusiness
✕ bizId 가 다를 경우에만 api 호출이 발생해야 한다. (5004 ms)
● useBusiness › bizId 가 다를 경우에만 api 호출이 발생해야 한다.
thrown: "Exceeded timeout of 5000 ms for a test.
Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."
28 |
29 | describe('useBusiness', () => {
> 30 | test('bizId 가 다를 경우에만 api 호출이 발생해야 한다.', async () => {
| ^
31 | BusinessApi.getBusiness.mockResolvedValue('hello world')
32 | const { waitFor, result, waitForNextUpdate } = renderHook(
33 | () => useBusiness({ bizId: 1 }),
at src/queries/useBusiness.test.js:30:5
at Object.<anonymous> (src/queries/useBusiness.test.js:29:1)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 12.639 s
Ran all test suites related to changed files.
Watch Usage: Press w to show more.
waitFor 에서 타임아웃 오류가 발생한다. 리액트 테스팅라이브러리가 아직 suspense 모드를 원활하게 지원하지 못하는 것 같다.(어쩌면 내가 방법을 모르는 것일지도ㅠ)
구글링을 해도 적절한 방법을 찾을 수 없었다;
참고로 커스텀훅에서 suspense 를 false 로 설정하면 테스트가 통과된다!
이 것 때문에 시간을 너무 많이 소비했다; suspense 모드를 테스트할 수 있는 방법은 숙제로 남겨두고 다음 작업을 이어서 해야겠다.