SoYoung210 / soso-tip

🍯소소한 팁들과 정리, 버그 해결기를 모아두는 레포
24 stars 0 forks source link

Jest cutomHook Test mock value not changed #44

Open SoYoung210 opened 4 years ago

SoYoung210 commented 4 years ago

Desc

custom hook에서 두 가지 이상의 테스트를 작성할 때 mocking 값이 변하지 않던 기이한 현상

개별적으로 하나씩 run시키면 모두 성공하나, 두개를 같이 돌릴 경우 실패

사용했던 코드들

#### Custom hooks ```ts // Custom hooks import useSWR from 'swr'; import { getDataSample, SomeData } from '@/api/someData; export const useSomeData = () => { const { data } = useSWR( 'keySample', getDataSample, { suspense: true }, ); return data?.map(value => ({ ...card, testValue: value.sample === '0', })); }; ``` #### mocking Target Function ```ts export const getDataSample = (): Promise => { // mockData with delay return new Promise(resolve => setTimeout(() => resolve(mockValue), 800)); }; ``` #### Test Code ```ts // test code describe('useSomeData', () => { afterEach(cleanup); test('test1', async () => { getDataSampleAPI.mockResolvedValueOnce([{ ...mockRankingCard, testValue: '0', }]); const { result } = renderHook(useSomeData); await act(() => { return new Promise(res => setTimeout(res, 900)); }); console.log('@@@@ first res', (result.current as any)[0].testValue); expect((result.current as any)[0].isInPromotion).toBe(true); }); test('test2', async () => { getDataSampleAPI.mockResolvedValueOnce([{ ...mockRankingCard, testValue: '10', }]); const { result } = renderHook(useSomeData); await act(() => { return new Promise(res => setTimeout(res, 900)); }); console.log('@@@@ second res', (result.current as any)[0].testValue); expect((result.current as any)[0].isInPromotion).toBe(true); }); }); ```

증상

console.log('@@@@ second res', (result.current as any)[0].testValue);값이 바뀌지 않았다. (첫번째 테스트 값에 의존적)

해결

Jest mock혹은 renderHook에서의 문제를 의심해보았지만 범인은 타이머

jest.useFakeTimers();

describe('useSomeData', () => {
  afterEach(cleanup);
  test('test1', async () => {
    const { result, waitForValueToChange } = renderHook(useSomeData);

    await waitForValueToChange(() => {
      act(() => { jest.runAllTimers(); });

      return result.current;
    });
     // 이후 코드
  })

  test('test2', async () => {
    const { result, waitForValueToChange } = renderHook(useSomeData);

    await waitForValueToChange(() => {
      act(() => { jest.runAllTimers(); });

      return result.current;
    });

     // 이후 코드
  })
})

timer mocking으로 해결

더 자세한 원인

Jest timer mocks를 참고해서 조사중..