Testing own custom React hook by using `@testing-library/react-hook` with Jest

Sometimes we create an own custom React hook for your own React application.And these hooks have a several fun […]

広告ここから
広告ここまで

目次

    Sometimes we create an own custom React hook for your own React application.
    And these hooks have a several functionality like handling state and dispatching Redux action and moe…
    We can test these hooks using @testing-library/react-hook.

    Install

    $ yarn add -D  react-@testing-library/react-hooks react-test-renderer

    Write a test for React hook

    In this post, we make a test code for the example custom hook.

    
    const useExampleModalHook = () => {
        const [modal, modalOpen] = useState(false)
        const open = useCallback(() => {
          modalOpen(true)
        }, [modalOpen])
        const close = useCallback(() => {
          modalOpen(false)
        }, [modalOpen])
        const toggle = useCallback(() => {
          modalOpen(!modal)
        }, [modal, modalOpen])
        return {
          modal,
          open,
          close,
          toggle,
        }
      }

    And this is a test code for the hook.

    import { renderHook, act } from '@testing-library/react-hooks';
    
    describe('useExampleModalHook', () => {
      let result = renderHook(() => useExampleModalHook()).result
      beforeEach(() => {
        result = renderHook(() => useExampleModalHook()).result
      })
      afterEach(() => {
        mockDispatch.mockClear();
      });
      it('should modal is false by default', () => {
        expect(result.current.modal).toEqual(false)
      })
      it('should modal is true when call open', () => {
        act(() => {
          result.current.open()
        })
        expect(result.current.modal).toEqual(true)
      })
      it('should modal is true when called toggle once', () => {
        act(() => {
          result.current.toggle()
        })
        expect(result.current.modal).toEqual(true)
      })
      it('should modal is true when called toggle once', () => {
        act(() => {
          result.current.toggle()
        })
        act(() => {
          result.current.toggle()
        })
        expect(result.current.modal).toEqual(false)
      })
    })

    renderHook will return own hook without creating any React Component.

    And use act, we can execute any hook function.

    With Redux (useDispatch / useSelector)

    If we want to test hook using Redux hooks, we need to mock by jest.

    export const exampleHookWithRedux = () => {
      const dispatch = useDispatch();
      const globalClose = useCallback(() => {
        dispatch(closeUserModal('username'));
      }, [dispatch]);
      return {
        dummy: useSelector((state: State) => state.modal),
        globalClose,
      }
    }

    This is a test code for the hook.

    const mockDispatch = jest.fn();
    const mockSelector = jest.fn().mockImplementation(() => ({
      status: '',
      result: '',
    }));
    jest.mock('react-redux', () => ({
      useDispatch: () => mockDispatch,
      useSelector: () => mockSelector(),
    }));
    
    
    describe('exampleHookWithRedux ', () => {
      let result = renderHook(() => exampleHookWithRedux ()).result
      beforeEach(() => {
        result = renderHook(() => exampleHookWithRedux ()).result
      })
      it('should modal is false by default', () => {
        expect(result.current.dummy).toEqual({
          status: '',
          result: '',
        })
      })
      it('should call dispatch function at once', () => {
        act(() => {
          result.current.globalClose()
        })
        expect(mockDispatch).toHaveBeenCalledTimes(1)
      })
      it('should call valid action', () => {
        act(() => {
          result.current.globalClose()
        })
        expect(mockDispatch).toHaveBeenCalledWith({
          type: 'CLOSE_USER_MODAL',
          payload: {
            username: 'username'
          }
        })
      })
      it('When selector return updated value, should get updated one', () => {
        mockSelector.mockImplementationOnce(() => ({
          status: 'loading',
          result: ''
        }))
        result = renderHook(() => exampleHookWithRedux ()).result
        expect(result.current.dummy).toEqual({
          status: 'loading',
          result: '',
        })
      })
    })

    広告ここから
    広告ここまで

    Random posts

    Home
    Search
    Bookmark